diff --git a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java index c7483c7c..7f9142d2 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java +++ b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java @@ -115,7 +115,6 @@ import java.util.concurrent.ConcurrentHashMap; initDb(APP); regAppLifeCallback(APP); initAria(); - amendTaskState(); } public Context getAPP() { @@ -137,6 +136,7 @@ import java.util.concurrent.ConcurrentHashMap; } } mDbWrapper = DelegateWrapper.init(context.getApplicationContext()); + amendTaskState(); } private void initAria() { diff --git a/Aria/src/main/java/com/arialyy/aria/core/common/FtpOption.java b/Aria/src/main/java/com/arialyy/aria/core/common/FtpOption.java index c162cd83..bc4fcf69 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/common/FtpOption.java +++ b/Aria/src/main/java/com/arialyy/aria/core/common/FtpOption.java @@ -21,6 +21,12 @@ import com.arialyy.aria.core.ProtocolType; import com.arialyy.aria.core.processor.IFtpUploadInterceptor; import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.CheckUtil; +import java.text.DateFormatSymbols; +import java.util.Collection; +import java.util.Locale; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.TreeMap; /** * Created by laoyuyu on 2018/3/9. @@ -37,6 +43,15 @@ public class FtpOption extends BaseOption { private int minPort, maxPort; private String activeExternalIPAddress; + //---------------- ftp client 配置信息 start + private String defaultDateFormatStr = null; + private String recentDateFormatStr = null; + private String serverLanguageCode = null; + private String shortMonthNames = null; + private String serverTimeZoneId = null; + private String systemKey = FTPServerIdentifier.SYST_UNIX; + //---------------- ftp client 配置信息 end + public FtpOption() { super(); } @@ -203,6 +218,78 @@ public class FtpOption extends BaseOption { return this; } + /** + * 设置ftp服务器所在的操作系统的标志,如果出现文件获取失败,请设置该标志为 + * 默认使用{@link FTPServerIdentifier#SYST_UNIX} + * + * @param identifier {@link FTPServerIdentifier} + */ + public FtpOption setServerIdentifier(String identifier) { + this.systemKey = identifier; + return this; + } + + /** + * 解析ftp信息时,默认的文件日期格式,如:setDefaultDateFormatStr("d MMM yyyy") + * + * @param defaultDateFormatStr 日期格式 + */ + public FtpOption setDefaultDateFormatStr(String defaultDateFormatStr) { + this.defaultDateFormatStr = defaultDateFormatStr; + return this; + } + + /** + * 解析ftp信息时,默认的文件修改日期格式,如:setRecentDateFormatStr("d MMM HH:mm") + * + * @param recentDateFormatStr 日期格式 + */ + public FtpOption setRecentDateFormatStr(String recentDateFormatStr) { + this.recentDateFormatStr = recentDateFormatStr; + return this; + } + + /** + * 设置服务器使用的时区,java.util.TimeZone,如:America/Chicago or Asia/Rangoon. + * + * @param serverTimeZoneId 时区 + */ + public void setServerTimeZoneId(String serverTimeZoneId) { + this.serverTimeZoneId = serverTimeZoneId; + } + + /** + *

+ * setter for the shortMonthNames property. + * This property allows the user to specify a set of month names + * used by the server that is different from those that may be + * specified using the {@link #setServerLanguageCode(String) serverLanguageCode} + * property. + *

+ * This should be a string containing twelve strings each composed of + * three characters, delimited by pipe (|) characters. Currently, + * only 8-bit ASCII characters are known to be supported. For example, + * a set of month names used by a hypothetical Icelandic FTP server might + * conceivably be specified as + * "jan|feb|mar|apr|maí|jún|júl|ágú|sep|okt|nóv|des". + *

+ * + * @param shortMonthNames The value to set to the shortMonthNames property. + */ + public void setShortMonthNames(String shortMonthNames) { + this.shortMonthNames = shortMonthNames; + } + + /** + * 设置服务器语言代码 + * + * @param serverLanguageCode {@link #LANGUAGE_CODE_MAP} + */ + public FtpOption setServerLanguageCode(String serverLanguageCode) { + this.serverLanguageCode = serverLanguageCode; + return this; + } + public void setUrlEntity(FtpUrlEntity urlEntity) { this.urlEntity = urlEntity; urlEntity.needLogin = isNeedLogin; @@ -218,4 +305,191 @@ public class FtpOption extends BaseOption { urlEntity.isImplicit = isImplicit; } } + + /** + * ftp 服务器所在的操作系统标志 + */ + public interface FTPServerIdentifier { + /** + * Identifier by which a unix-based ftp server is known throughout + * the commons-net ftp system. + */ + String SYST_UNIX = "UNIX"; + + /** + * Identifier for alternate UNIX parser; same as {@link #SYST_UNIX} but leading spaces are + * trimmed from file names. This is to maintain backwards compatibility with + * the original behaviour of the parser which ignored multiple spaces between the date + * and the start of the file name. + * + * @since 3.4 + */ + String SYST_UNIX_TRIM_LEADING = "UNIX_LTRIM"; + + /** + * Identifier by which a vms-based ftp server is known throughout + * the commons-net ftp system. + */ + String SYST_VMS = "VMS"; + + /** + * Identifier by which a WindowsNT-based ftp server is known throughout + * the commons-net ftp system. + */ + String SYST_NT = "WINDOWS"; + + /** + * Identifier by which an OS/2-based ftp server is known throughout + * the commons-net ftp system. + */ + String SYST_OS2 = "OS/2"; + + /** + * Identifier by which an OS/400-based ftp server is known throughout + * the commons-net ftp system. + */ + String SYST_OS400 = "OS/400"; + + /** + * Identifier by which an AS/400-based ftp server is known throughout + * the commons-net ftp system. + */ + String SYST_AS400 = "AS/400"; + + /** + * Identifier by which an MVS-based ftp server is known throughout + * the commons-net ftp system. + */ + String SYST_MVS = "MVS"; + + /** + * Some servers return an "UNKNOWN Type: L8" message + * in response to the SYST command. We set these to be a Unix-type system. + * This may happen if the ftpd in question was compiled without system + * information. + * + * NET-230 - Updated to be UPPERCASE so that the check done in + * createFileEntryParser will succeed. + * + * @since 1.5 + */ + String SYST_L8 = "TYPE: L8"; + + /** + * Identifier by which an Netware-based ftp server is known throughout + * the commons-net ftp system. + * + * @since 1.5 + */ + String SYST_NETWARE = "NETWARE"; + + /** + * Identifier by which a Mac pre OS-X -based ftp server is known throughout + * the commons-net ftp system. + * + * @since 3.1 + */ + // Full string is "MACOS Peter's Server"; the substring below should be enough + String SYST_MACOS_PETER = "MACOS PETER"; // NET-436 + } + + /** + * 支持的语言代码 + */ + private static final Map LANGUAGE_CODE_MAP = new TreeMap<>(); + + static { + + // if there are other commonly used month name encodings which + // correspond to particular locales, please add them here. + + // many locales code short names for months as all three letters + // these we handle simply. + LANGUAGE_CODE_MAP.put("en", Locale.ENGLISH); + LANGUAGE_CODE_MAP.put("de", Locale.GERMAN); + LANGUAGE_CODE_MAP.put("it", Locale.ITALIAN); + LANGUAGE_CODE_MAP.put("es", new Locale("es", "", "")); // spanish + LANGUAGE_CODE_MAP.put("pt", new Locale("pt", "", "")); // portuguese + LANGUAGE_CODE_MAP.put("da", new Locale("da", "", "")); // danish + LANGUAGE_CODE_MAP.put("sv", new Locale("sv", "", "")); // swedish + LANGUAGE_CODE_MAP.put("no", new Locale("no", "", "")); // norwegian + LANGUAGE_CODE_MAP.put("nl", new Locale("nl", "", "")); // dutch + LANGUAGE_CODE_MAP.put("ro", new Locale("ro", "", "")); // romanian + LANGUAGE_CODE_MAP.put("sq", new Locale("sq", "", "")); // albanian + LANGUAGE_CODE_MAP.put("sh", new Locale("sh", "", "")); // serbo-croatian + LANGUAGE_CODE_MAP.put("sk", new Locale("sk", "", "")); // slovak + LANGUAGE_CODE_MAP.put("sl", new Locale("sl", "", "")); // slovenian + + // some don't + LANGUAGE_CODE_MAP.put("fr", + "jan|f\u00e9v|mar|avr|mai|jun|jui|ao\u00fb|sep|oct|nov|d\u00e9c"); //french + } + + /** + * Looks up the supplied language code in the internally maintained table of + * language codes. Returns a DateFormatSymbols object configured with + * short month names corresponding to the code. If there is no corresponding + * entry in the table, the object returned will be that for + * Locale.US + * + * @param languageCode See {@link #setServerLanguageCode(String) serverLanguageCode} + * @return a DateFormatSymbols object configured with short month names + * corresponding to the supplied code, or with month names for + * Locale.US if there is no corresponding entry in the internal + * table. + */ + public static DateFormatSymbols lookupDateFormatSymbols(String languageCode) { + Object lang = LANGUAGE_CODE_MAP.get(languageCode); + if (lang != null) { + if (lang instanceof Locale) { + return new DateFormatSymbols((Locale) lang); + } else if (lang instanceof String) { + return getDateFormatSymbols((String) lang); + } + } + return new DateFormatSymbols(Locale.US); + } + + /** + * Returns a DateFormatSymbols object configured with short month names + * as in the supplied string + * + * @param shortmonths This should be as described in + * {@link #setShortMonthNames(String) shortMonthNames} + * @return a DateFormatSymbols object configured with short month names + * as in the supplied string + */ + public static DateFormatSymbols getDateFormatSymbols(String shortmonths) { + String[] months = splitShortMonthString(shortmonths); + DateFormatSymbols dfs = new DateFormatSymbols(Locale.US); + dfs.setShortMonths(months); + return dfs; + } + + private static String[] splitShortMonthString(String shortmonths) { + StringTokenizer st = new StringTokenizer(shortmonths, "|"); + int monthcnt = st.countTokens(); + if (12 != monthcnt) { + throw new IllegalArgumentException("expecting a pipe-delimited string containing 12 tokens"); + } + String[] months = new String[13]; + int pos = 0; + while (st.hasMoreTokens()) { + months[pos++] = st.nextToken(); + } + months[pos] = ""; + return months; + } + + /** + * Returns a Collection of all the language codes currently supported + * by this class. See {@link #setServerLanguageCode(String) serverLanguageCode} + * for a functional descrption of language codes within this system. + * + * @return a Collection of all the language codes currently supported + * by this class + */ + public static Collection getSupportedLanguageCodes() { + return LANGUAGE_CODE_MAP.keySet(); + } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/common/controller/BuilderController.java b/Aria/src/main/java/com/arialyy/aria/core/common/controller/BuilderController.java index 70002c01..586b243d 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/common/controller/BuilderController.java +++ b/Aria/src/main/java/com/arialyy/aria/core/common/controller/BuilderController.java @@ -30,7 +30,7 @@ public final class BuilderController extends FeatureController implements IStart } /** - * 添加任务 + * 添加任务,只添加任务不进行下载 * * @return 正常添加,返回任务id,否则返回-1 */ diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java index 09c58c08..5382cd4f 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java @@ -181,7 +181,7 @@ public class DownloadReceiver extends AbsReceiver { } } } else { - ALog.e(TAG, "没有Aria的注解方法"); + ALog.e(TAG, "没有Aria的注解方法,详情见:https://aria.laoyuyu.me/aria_doc/other/annotaion_invalid.html"); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java index c8c8ec2e..7b5aea7b 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java @@ -267,7 +267,7 @@ public class UploadReceiver extends AbsReceiver { } } } else { - ALog.e(TAG, "没有Aria的注解方法"); + ALog.e(TAG, "没有Aria的注解方法,详情见:https://aria.laoyuyu.me/aria_doc/other/annotaion_invalid.html"); } } diff --git a/AriaFtpPlug/.gitignore b/AriaFtpPlug/.gitignore deleted file mode 100644 index 796b96d1..00000000 --- a/AriaFtpPlug/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/AriaFtpPlug/bintray-release.gradle b/AriaFtpPlug/bintray-release.gradle deleted file mode 100644 index 43708895..00000000 --- a/AriaFtpPlug/bintray-release.gradle +++ /dev/null @@ -1,11 +0,0 @@ -apply plugin: 'com.novoda.bintray-release' -publish { - artifactId = 'aria-ftp-plug' - userOrg = rootProject.ext.userOrg - groupId = rootProject.ext.groupId - uploadName = 'FtpPlug' - publishVersion = rootProject.ext.publishVersion - desc = rootProject.ext.desc - website = rootProject.ext.website - licences = rootProject.ext.licences -} \ No newline at end of file diff --git a/AriaFtpPlug/build.gradle b/AriaFtpPlug/build.gradle deleted file mode 100644 index 71876c9d..00000000 --- a/AriaFtpPlug/build.gradle +++ /dev/null @@ -1,14 +0,0 @@ -apply plugin: 'java' - -tasks.withType(JavaCompile) { - options.encoding = "UTF-8" -} - -sourceCompatibility = JavaVersion.VERSION_1_7 -targetCompatibility = JavaVersion.VERSION_1_7 - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) -} - -//apply from: 'bintray-release.gradle' \ No newline at end of file diff --git a/AriaFtpPlug/proguard-rules.pro b/AriaFtpPlug/proguard-rules.pro deleted file mode 100644 index 36df18ca..00000000 --- a/AriaFtpPlug/proguard-rules.pro +++ /dev/null @@ -1,25 +0,0 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in E:\sdk/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the proguardFiles -# directive in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/DatagramSocketClient.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/DatagramSocketClient.java deleted file mode 100644 index 2ddf9be4..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/DatagramSocketClient.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net; - -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.SocketException; -import java.nio.charset.Charset; - -/*** - * The DatagramSocketClient provides the basic operations that are required - * of client objects accessing datagram sockets. It is meant to be - * subclassed to avoid having to rewrite the same code over and over again - * to open a socket, close a socket, set timeouts, etc. Of special note - * is the {@link #setDatagramSocketFactory setDatagramSocketFactory } - * method, which allows you to control the type of DatagramSocket the - * DatagramSocketClient creates for network communications. This is - * especially useful for adding things like proxy support as well as better - * support for applets. For - * example, you could create a - * {@link DatagramSocketFactory} - * that - * requests browser security capabilities before creating a socket. - * All classes derived from DatagramSocketClient should use the - * {@link #_socketFactory_ _socketFactory_ } member variable to - * create DatagramSocket instances rather than instantiating - * them by directly invoking a constructor. By honoring this contract - * you guarantee that a user will always be able to provide his own - * Socket implementations by substituting his own SocketFactory. - * - * - * @see DatagramSocketFactory - ***/ - -public abstract class DatagramSocketClient { - /*** - * The default DatagramSocketFactory shared by all DatagramSocketClient - * instances. - ***/ - private static final DatagramSocketFactory __DEFAULT_SOCKET_FACTORY = - new DefaultDatagramSocketFactory(); - - /** - * Charset to use for byte IO. - */ - private Charset charset = Charset.defaultCharset(); - - /*** The timeout to use after opening a socket. ***/ - protected int _timeout_; - - /*** The datagram socket used for the connection. ***/ - protected DatagramSocket _socket_; - - /*** - * A status variable indicating if the client's socket is currently open. - ***/ - protected boolean _isOpen_; - - /*** The datagram socket's DatagramSocketFactory. ***/ - protected DatagramSocketFactory _socketFactory_; - - /*** - * Default constructor for DatagramSocketClient. Initializes - * _socket_ to null, _timeout_ to 0, and _isOpen_ to false. - ***/ - public DatagramSocketClient() { - _socket_ = null; - _timeout_ = 0; - _isOpen_ = false; - _socketFactory_ = __DEFAULT_SOCKET_FACTORY; - } - - /*** - * Opens a DatagramSocket on the local host at the first available port. - * Also sets the timeout on the socket to the default timeout set - * by {@link #setDefaultTimeout setDefaultTimeout() }. - *

- * _isOpen_ is set to true after calling this method and _socket_ - * is set to the newly opened socket. - * - * @throws SocketException If the socket could not be opened or the - * timeout could not be set. - ***/ - public void open() throws SocketException { - _socket_ = _socketFactory_.createDatagramSocket(); - _socket_.setSoTimeout(_timeout_); - _isOpen_ = true; - } - - /*** - * Opens a DatagramSocket on the local host at a specified port. - * Also sets the timeout on the socket to the default timeout set - * by {@link #setDefaultTimeout setDefaultTimeout() }. - *

- * _isOpen_ is set to true after calling this method and _socket_ - * is set to the newly opened socket. - * - * @param port The port to use for the socket. - * @throws SocketException If the socket could not be opened or the - * timeout could not be set. - ***/ - public void open(int port) throws SocketException { - _socket_ = _socketFactory_.createDatagramSocket(port); - _socket_.setSoTimeout(_timeout_); - _isOpen_ = true; - } - - /*** - * Opens a DatagramSocket at the specified address on the local host - * at a specified port. - * Also sets the timeout on the socket to the default timeout set - * by {@link #setDefaultTimeout setDefaultTimeout() }. - *

- * _isOpen_ is set to true after calling this method and _socket_ - * is set to the newly opened socket. - * - * @param port The port to use for the socket. - * @param laddr The local address to use. - * @throws SocketException If the socket could not be opened or the - * timeout could not be set. - ***/ - public void open(int port, InetAddress laddr) throws SocketException { - _socket_ = _socketFactory_.createDatagramSocket(port, laddr); - _socket_.setSoTimeout(_timeout_); - _isOpen_ = true; - } - - /*** - * Closes the DatagramSocket used for the connection. - * You should call this method after you've finished using the class - * instance and also before you call {@link #open open() } - * again. _isOpen_ is set to false and _socket_ is set to null. - ***/ - public void close() { - if (_socket_ != null) { - _socket_.close(); - } - _socket_ = null; - _isOpen_ = false; - } - - /*** - * Returns true if the client has a currently open socket. - * - * @return True if the client has a currently open socket, false otherwise. - ***/ - public boolean isOpen() { - return _isOpen_; - } - - /*** - * Set the default timeout in milliseconds to use when opening a socket. - * After a call to open, the timeout for the socket is set using this value. - * This method should be used prior to a call to {@link #open open()} - * and should not be confused with {@link #setSoTimeout setSoTimeout()} - * which operates on the currently open socket. _timeout_ contains - * the new timeout value. - * - * @param timeout The timeout in milliseconds to use for the datagram socket - * connection. - ***/ - public void setDefaultTimeout(int timeout) { - _timeout_ = timeout; - } - - /*** - * Returns the default timeout in milliseconds that is used when - * opening a socket. - * - * @return The default timeout in milliseconds that is used when - * opening a socket. - ***/ - public int getDefaultTimeout() { - return _timeout_; - } - - /*** - * Set the timeout in milliseconds of a currently open connection. - * Only call this method after a connection has been opened - * by {@link #open open()}. - * - * @param timeout The timeout in milliseconds to use for the currently - * open datagram socket connection. - * @throws SocketException if an error setting the timeout - ***/ - public void setSoTimeout(int timeout) throws SocketException { - _socket_.setSoTimeout(timeout); - } - - /*** - * Returns the timeout in milliseconds of the currently opened socket. - * If you call this method when the client socket is not open, - * a NullPointerException is thrown. - * - * @return The timeout in milliseconds of the currently opened socket. - * @throws SocketException if an error getting the timeout - ***/ - public int getSoTimeout() throws SocketException { - return _socket_.getSoTimeout(); - } - - /*** - * Returns the port number of the open socket on the local host used - * for the connection. If you call this method when the client socket - * is not open, a NullPointerException is thrown. - * - * @return The port number of the open socket on the local host used - * for the connection. - ***/ - public int getLocalPort() { - return _socket_.getLocalPort(); - } - - /*** - * Returns the local address to which the client's socket is bound. - * If you call this method when the client socket is not open, a - * NullPointerException is thrown. - * - * @return The local address to which the client's socket is bound. - ***/ - public InetAddress getLocalAddress() { - return _socket_.getLocalAddress(); - } - - /*** - * Sets the DatagramSocketFactory used by the DatagramSocketClient - * to open DatagramSockets. If the factory value is null, then a default - * factory is used (only do this to reset the factory after having - * previously altered it). - * - * @param factory The new DatagramSocketFactory the DatagramSocketClient - * should use. - ***/ - public void setDatagramSocketFactory(DatagramSocketFactory factory) { - if (factory == null) { - _socketFactory_ = __DEFAULT_SOCKET_FACTORY; - } else { - _socketFactory_ = factory; - } - } - - /** - * Gets the charset name. - * - * @return the charset name. - * @since 3.3 - * TODO Will be deprecated once the code requires Java 1.6 as a mininmum - */ - public String getCharsetName() { - return charset.name(); - } - - /** - * Gets the charset. - * - * @return the charset. - * @since 3.3 - */ - public Charset getCharset() { - return charset; - } - - /** - * Sets the charset. - * - * @param charset the charset. - * @since 3.3 - */ - public void setCharset(Charset charset) { - this.charset = charset; - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/DatagramSocketFactory.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/DatagramSocketFactory.java deleted file mode 100644 index 385cceb4..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/DatagramSocketFactory.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net; - -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.SocketException; - -/*** - * The DatagramSocketFactory interface provides a means for the - * programmer to control the creation of datagram sockets and - * provide his own DatagramSocket implementations for use by all - * classes derived from - * {@link DatagramSocketClient} - * . - * This allows you to provide your own DatagramSocket implementations and - * to perform security checks or browser capability requests before - * creating a DatagramSocket. - * - * - ***/ - -public interface DatagramSocketFactory { - - /*** - * Creates a DatagramSocket on the local host at the first available port. - * @return the socket - * - * @throws SocketException If the socket could not be created. - ***/ - public DatagramSocket createDatagramSocket() throws SocketException; - - /*** - * Creates a DatagramSocket on the local host at a specified port. - * - * @param port The port to use for the socket. - * @return the socket - * @throws SocketException If the socket could not be created. - ***/ - public DatagramSocket createDatagramSocket(int port) throws SocketException; - - /*** - * Creates a DatagramSocket at the specified address on the local host - * at a specified port. - * - * @param port The port to use for the socket. - * @param laddr The local address to use. - * @return the socket - * @throws SocketException If the socket could not be created. - ***/ - public DatagramSocket createDatagramSocket(int port, InetAddress laddr) throws SocketException; -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/DefaultDatagramSocketFactory.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/DefaultDatagramSocketFactory.java deleted file mode 100644 index e269124d..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/DefaultDatagramSocketFactory.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net; - -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.SocketException; - -/*** - * DefaultDatagramSocketFactory implements the DatagramSocketFactory - * interface by simply wrapping the java.net.DatagramSocket - * constructors. It is the default DatagramSocketFactory used by - * {@link DatagramSocketClient} - * implementations. - * - * - * @see DatagramSocketFactory - * @see DatagramSocketClient - * @see DatagramSocketClient#setDatagramSocketFactory - ***/ - -public class DefaultDatagramSocketFactory implements DatagramSocketFactory { - - /*** - * Creates a DatagramSocket on the local host at the first available port. - * @return a new DatagramSocket - * @throws SocketException If the socket could not be created. - ***/ - @Override public DatagramSocket createDatagramSocket() throws SocketException { - return new DatagramSocket(); - } - - /*** - * Creates a DatagramSocket on the local host at a specified port. - * - * @param port The port to use for the socket. - * @return a new DatagramSocket - * @throws SocketException If the socket could not be created. - ***/ - @Override public DatagramSocket createDatagramSocket(int port) throws SocketException { - return new DatagramSocket(port); - } - - /*** - * Creates a DatagramSocket at the specified address on the local host - * at a specified port. - * - * @param port The port to use for the socket. - * @param laddr The local address to use. - * @return a new DatagramSocket - * @throws SocketException If the socket could not be created. - ***/ - @Override public DatagramSocket createDatagramSocket(int port, InetAddress laddr) - throws SocketException { - return new DatagramSocket(port, laddr); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/DefaultSocketFactory.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/DefaultSocketFactory.java deleted file mode 100644 index 1fec9085..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/DefaultSocketFactory.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.UnknownHostException; - -import javax.net.SocketFactory; - -/*** - * DefaultSocketFactory implements the SocketFactory interface by - * simply wrapping the java.net.Socket and java.net.ServerSocket - * constructors. It is the default SocketFactory used by - * {@link SocketClient} - * implementations. - * - * - * @see SocketFactory - * @see SocketClient - * @see SocketClient#setSocketFactory - ***/ - -public class DefaultSocketFactory extends SocketFactory { - /** The proxy to use when creating new sockets. */ - private final Proxy connProxy; - - /** - * The default constructor. - */ - public DefaultSocketFactory() { - this(null); - } - - /** - * A constructor for sockets with proxy support. - * - * @param proxy The Proxy to use when creating new Sockets. - * @since 3.2 - */ - public DefaultSocketFactory(Proxy proxy) { - connProxy = proxy; - } - - /** - * Creates an unconnected Socket. - * - * @return A new unconnected Socket. - * @throws IOException If an I/O error occurs while creating the Socket. - * @since 3.2 - */ - @Override public Socket createSocket() throws IOException { - if (connProxy != null) { - return new Socket(connProxy); - } - return new Socket(); - } - - /*** - * Creates a Socket connected to the given host and port. - * - * @param host The hostname to connect to. - * @param port The port to connect to. - * @return A Socket connected to the given host and port. - * @throws UnknownHostException If the hostname cannot be resolved. - * @throws IOException If an I/O error occurs while creating the Socket. - ***/ - @Override public Socket createSocket(String host, int port) - throws UnknownHostException, IOException { - if (connProxy != null) { - Socket s = new Socket(connProxy); - s.connect(new InetSocketAddress(host, port)); - return s; - } - return new Socket(host, port); - } - - /*** - * Creates a Socket connected to the given host and port. - * - * @param address The address of the host to connect to. - * @param port The port to connect to. - * @return A Socket connected to the given host and port. - * @throws IOException If an I/O error occurs while creating the Socket. - ***/ - @Override public Socket createSocket(InetAddress address, int port) throws IOException { - if (connProxy != null) { - Socket s = new Socket(connProxy); - s.connect(new InetSocketAddress(address, port)); - return s; - } - return new Socket(address, port); - } - - /*** - * Creates a Socket connected to the given host and port and - * originating from the specified local address and port. - * - * @param host The hostname to connect to. - * @param port The port to connect to. - * @param localAddr The local address to use. - * @param localPort The local port to use. - * @return A Socket connected to the given host and port. - * @throws UnknownHostException If the hostname cannot be resolved. - * @throws IOException If an I/O error occurs while creating the Socket. - ***/ - @Override public Socket createSocket(String host, int port, InetAddress localAddr, int localPort) - throws UnknownHostException, IOException { - if (connProxy != null) { - Socket s = new Socket(connProxy); - s.bind(new InetSocketAddress(localAddr, localPort)); - s.connect(new InetSocketAddress(host, port)); - return s; - } - return new Socket(host, port, localAddr, localPort); - } - - /*** - * Creates a Socket connected to the given host and port and - * originating from the specified local address and port. - * - * @param address The address of the host to connect to. - * @param port The port to connect to. - * @param localAddr The local address to use. - * @param localPort The local port to use. - * @return A Socket connected to the given host and port. - * @throws IOException If an I/O error occurs while creating the Socket. - ***/ - @Override public Socket createSocket(InetAddress address, int port, InetAddress localAddr, - int localPort) throws IOException { - if (connProxy != null) { - Socket s = new Socket(connProxy); - s.bind(new InetSocketAddress(localAddr, localPort)); - s.connect(new InetSocketAddress(address, port)); - return s; - } - return new Socket(address, port, localAddr, localPort); - } - - /*** - * Creates a ServerSocket bound to a specified port. A port - * of 0 will create the ServerSocket on a system-determined free port. - * - * @param port The port on which to listen, or 0 to use any free port. - * @return A ServerSocket that will listen on a specified port. - * @throws IOException If an I/O error occurs while creating - * the ServerSocket. - ***/ - public ServerSocket createServerSocket(int port) throws IOException { - return new ServerSocket(port); - } - - /*** - * Creates a ServerSocket bound to a specified port with a given - * maximum queue length for incoming connections. A port of 0 will - * create the ServerSocket on a system-determined free port. - * - * @param port The port on which to listen, or 0 to use any free port. - * @param backlog The maximum length of the queue for incoming connections. - * @return A ServerSocket that will listen on a specified port. - * @throws IOException If an I/O error occurs while creating - * the ServerSocket. - ***/ - public ServerSocket createServerSocket(int port, int backlog) throws IOException { - return new ServerSocket(port, backlog); - } - - /*** - * Creates a ServerSocket bound to a specified port on a given local - * address with a given maximum queue length for incoming connections. - * A port of 0 will - * create the ServerSocket on a system-determined free port. - * - * @param port The port on which to listen, or 0 to use any free port. - * @param backlog The maximum length of the queue for incoming connections. - * @param bindAddr The local address to which the ServerSocket should bind. - * @return A ServerSocket that will listen on a specified port. - * @throws IOException If an I/O error occurs while creating - * the ServerSocket. - ***/ - public ServerSocket createServerSocket(int port, int backlog, InetAddress bindAddr) - throws IOException { - return new ServerSocket(port, backlog, bindAddr); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/MalformedServerReplyException.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/MalformedServerReplyException.java deleted file mode 100644 index c63818fc..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/MalformedServerReplyException.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net; - -import java.io.IOException; - -/*** - * This exception is used to indicate that the reply from a server - * could not be interpreted. Most of the NetComponents classes attempt - * to be as lenient as possible when receiving server replies. Many - * server implementations deviate from IETF protocol specifications, making - * it necessary to be as flexible as possible. However, there will be - * certain situations where it is not possible to continue an operation - * because the server reply could not be interpreted in a meaningful manner. - * In these cases, a MalformedServerReplyException should be thrown. - * - * - ***/ - -public class MalformedServerReplyException extends IOException { - - private static final long serialVersionUID = 6006765264250543945L; - - /*** Constructs a MalformedServerReplyException with no message ***/ - public MalformedServerReplyException() { - super(); - } - - /*** - * Constructs a MalformedServerReplyException with a specified message. - * - * @param message The message explaining the reason for the exception. - ***/ - public MalformedServerReplyException(String message) { - super(message); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/PrintCommandListener.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/PrintCommandListener.java deleted file mode 100644 index 14f92c78..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/PrintCommandListener.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net; - -import java.io.PrintStream; -import java.io.PrintWriter; - -/*** - * This is a support class for some of the example programs. It is - * a sample implementation of the ProtocolCommandListener interface - * which just prints out to a specified stream all command/reply traffic. - * - * @since 2.0 - ***/ - -public class PrintCommandListener implements ProtocolCommandListener { - private final PrintWriter __writer; - private final boolean __nologin; - private final char __eolMarker; - private final boolean __directionMarker; - - /** - * Create the default instance which prints everything. - * - * @param stream where to write the commands and responses - * e.g. System.out - * @since 3.0 - */ - public PrintCommandListener(PrintStream stream) { - this(new PrintWriter(stream)); - } - - /** - * Create an instance which optionally suppresses login command text - * and indicates where the EOL starts with the specified character. - * - * @param stream where to write the commands and responses - * @param suppressLogin if {@code true}, only print command name for login - * @since 3.0 - */ - public PrintCommandListener(PrintStream stream, boolean suppressLogin) { - this(new PrintWriter(stream), suppressLogin); - } - - /** - * Create an instance which optionally suppresses login command text - * and indicates where the EOL starts with the specified character. - * - * @param stream where to write the commands and responses - * @param suppressLogin if {@code true}, only print command name for login - * @param eolMarker if non-zero, add a marker just before the EOL. - * @since 3.0 - */ - public PrintCommandListener(PrintStream stream, boolean suppressLogin, char eolMarker) { - this(new PrintWriter(stream), suppressLogin, eolMarker); - } - - /** - * Create an instance which optionally suppresses login command text - * and indicates where the EOL starts with the specified character. - * - * @param stream where to write the commands and responses - * @param suppressLogin if {@code true}, only print command name for login - * @param eolMarker if non-zero, add a marker just before the EOL. - * @param showDirection if {@code true}, add {@code "> "} or {@code "< "} as appropriate to the - * output - * @since 3.0 - */ - public PrintCommandListener(PrintStream stream, boolean suppressLogin, char eolMarker, - boolean showDirection) { - this(new PrintWriter(stream), suppressLogin, eolMarker, showDirection); - } - - /** - * Create the default instance which prints everything. - * - * @param writer where to write the commands and responses - */ - public PrintCommandListener(PrintWriter writer) { - this(writer, false); - } - - /** - * Create an instance which optionally suppresses login command text. - * - * @param writer where to write the commands and responses - * @param suppressLogin if {@code true}, only print command name for login - * @since 3.0 - */ - public PrintCommandListener(PrintWriter writer, boolean suppressLogin) { - this(writer, suppressLogin, (char) 0); - } - - /** - * Create an instance which optionally suppresses login command text - * and indicates where the EOL starts with the specified character. - * - * @param writer where to write the commands and responses - * @param suppressLogin if {@code true}, only print command name for login - * @param eolMarker if non-zero, add a marker just before the EOL. - * @since 3.0 - */ - public PrintCommandListener(PrintWriter writer, boolean suppressLogin, char eolMarker) { - this(writer, suppressLogin, eolMarker, false); - } - - /** - * Create an instance which optionally suppresses login command text - * and indicates where the EOL starts with the specified character. - * - * @param writer where to write the commands and responses - * @param suppressLogin if {@code true}, only print command name for login - * @param eolMarker if non-zero, add a marker just before the EOL. - * @param showDirection if {@code true}, add {@code ">} " or {@code "< "} as appropriate to the - * output - * @since 3.0 - */ - public PrintCommandListener(PrintWriter writer, boolean suppressLogin, char eolMarker, - boolean showDirection) { - __writer = writer; - __nologin = suppressLogin; - __eolMarker = eolMarker; - __directionMarker = showDirection; - } - - @Override public void protocolCommandSent(ProtocolCommandEvent event) { - if (__directionMarker) { - __writer.print("> "); - } - if (__nologin) { - String cmd = event.getCommand(); - if ("PASS".equalsIgnoreCase(cmd) || "USER".equalsIgnoreCase(cmd)) { - __writer.print(cmd); - __writer.println(" *******"); // Don't bother with EOL marker for this! - } else { - final String IMAP_LOGIN = "LOGIN"; - if (IMAP_LOGIN.equalsIgnoreCase(cmd)) { // IMAP - String msg = event.getMessage(); - msg = msg.substring(0, msg.indexOf(IMAP_LOGIN) + IMAP_LOGIN.length()); - __writer.print(msg); - __writer.println(" *******"); // Don't bother with EOL marker for this! - } else { - __writer.print(getPrintableString(event.getMessage())); - } - } - } else { - __writer.print(getPrintableString(event.getMessage())); - } - __writer.flush(); - } - - private String getPrintableString(String msg) { - if (__eolMarker == 0) { - return msg; - } - int pos = msg.indexOf(SocketClient.NETASCII_EOL); - if (pos > 0) { - StringBuilder sb = new StringBuilder(); - sb.append(msg.substring(0, pos)); - sb.append(__eolMarker); - sb.append(msg.substring(pos)); - return sb.toString(); - } - return msg; - } - - @Override public void protocolReplyReceived(ProtocolCommandEvent event) { - if (__directionMarker) { - __writer.print("< "); - } - __writer.print(event.getMessage()); - __writer.flush(); - } -} - diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ProtocolCommandEvent.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ProtocolCommandEvent.java deleted file mode 100644 index 9f0154e7..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ProtocolCommandEvent.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net; - -import java.util.EventObject; - -/*** - * There exists a large class of IETF protocols that work by sending an - * ASCII text command and arguments to a server, and then receiving an - * ASCII text reply. For debugging and other purposes, it is extremely - * useful to log or keep track of the contents of the protocol messages. - * The ProtocolCommandEvent class coupled with the - * {@link ProtocolCommandListener} - * interface facilitate this process. - * - * - * @see ProtocolCommandListener - * @see ProtocolCommandSupport - ***/ - -public class ProtocolCommandEvent extends EventObject { - private static final long serialVersionUID = 403743538418947240L; - - private final int __replyCode; - private final boolean __isCommand; - private final String __message, __command; - - /*** - * Creates a ProtocolCommandEvent signalling a command was sent to - * the server. ProtocolCommandEvents created with this constructor - * should only be sent after a command has been sent, but before the - * reply has been received. - * - * @param source The source of the event. - * @param command The string representation of the command type sent, not - * including the arguments (e.g., "STAT" or "GET"). - * @param message The entire command string verbatim as sent to the server, - * including all arguments. - ***/ - public ProtocolCommandEvent(Object source, String command, String message) { - super(source); - __replyCode = 0; - __message = message; - __isCommand = true; - __command = command; - } - - /*** - * Creates a ProtocolCommandEvent signalling a reply to a command was - * received. ProtocolCommandEvents created with this constructor - * should only be sent after a complete command reply has been received - * fromt a server. - * - * @param source The source of the event. - * @param replyCode The integer code indicating the natureof the reply. - * This will be the protocol integer value for protocols - * that use integer reply codes, or the reply class constant - * corresponding to the reply for protocols like POP3 that use - * strings like OK rather than integer codes (i.e., POP3Repy.OK). - * @param message The entire reply as received from the server. - ***/ - public ProtocolCommandEvent(Object source, int replyCode, String message) { - super(source); - __replyCode = replyCode; - __message = message; - __isCommand = false; - __command = null; - } - - /*** - * Returns the string representation of the command type sent (e.g., "STAT" - * or "GET"). If the ProtocolCommandEvent is a reply event, then null - * is returned. - * - * @return The string representation of the command type sent, or null - * if this is a reply event. - ***/ - public String getCommand() { - return __command; - } - - /*** - * Returns the reply code of the received server reply. Undefined if - * this is not a reply event. - * - * @return The reply code of the received server reply. Undefined if - * not a reply event. - ***/ - public int getReplyCode() { - return __replyCode; - } - - /*** - * Returns true if the ProtocolCommandEvent was generated as a result - * of sending a command. - * - * @return true If the ProtocolCommandEvent was generated as a result - * of sending a command. False otherwise. - ***/ - public boolean isCommand() { - return __isCommand; - } - - /*** - * Returns true if the ProtocolCommandEvent was generated as a result - * of receiving a reply. - * - * @return true If the ProtocolCommandEvent was generated as a result - * of receiving a reply. False otherwise. - ***/ - public boolean isReply() { - return !isCommand(); - } - - /*** - * Returns the entire message sent to or received from the server. - * Includes the line terminator. - * - * @return The entire message sent to or received from the server. - ***/ - public String getMessage() { - return __message; - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ProtocolCommandListener.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ProtocolCommandListener.java deleted file mode 100644 index 12f8e00e..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ProtocolCommandListener.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net; - -import aria.apache.commons.net.ftp.FTPClient; -import java.util.EventListener; - -/*** - * There exists a large class of IETF protocols that work by sending an - * ASCII text command and arguments to a server, and then receiving an - * ASCII text reply. For debugging and other purposes, it is extremely - * useful to log or keep track of the contents of the protocol messages. - * The ProtocolCommandListener interface coupled with the - * {@link ProtocolCommandEvent} class facilitate this process. - *

- * To receive ProtocolCommandEvents, you merely implement the - * ProtocolCommandListener interface and register the class as a listener - * with a ProtocolCommandEvent source such as - * {@link FTPClient}. - * - * - * @see ProtocolCommandEvent - * @see ProtocolCommandSupport - ***/ - -public interface ProtocolCommandListener extends EventListener { - - /*** - * This method is invoked by a ProtocolCommandEvent source after - * sending a protocol command to a server. - * - * @param event The ProtocolCommandEvent fired. - ***/ - public void protocolCommandSent(ProtocolCommandEvent event); - - /*** - * This method is invoked by a ProtocolCommandEvent source after - * receiving a reply from a server. - * - * @param event The ProtocolCommandEvent fired. - ***/ - public void protocolReplyReceived(ProtocolCommandEvent event); -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ProtocolCommandSupport.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ProtocolCommandSupport.java deleted file mode 100644 index 01b1888e..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ProtocolCommandSupport.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net; - -import java.io.Serializable; -import java.util.EventListener; - -import aria.apache.commons.net.util.ListenerList; - -/*** - * ProtocolCommandSupport is a convenience class for managing a list of - * ProtocolCommandListeners and firing ProtocolCommandEvents. You can - * simply delegate ProtocolCommandEvent firing and listener - * registering/unregistering tasks to this class. - * - * - * @see ProtocolCommandEvent - * @see ProtocolCommandListener - ***/ - -public class ProtocolCommandSupport implements Serializable { - private static final long serialVersionUID = -8017692739988399978L; - - private final Object __source; - private final ListenerList __listeners; - - /*** - * Creates a ProtocolCommandSupport instance using the indicated source - * as the source of ProtocolCommandEvents. - * - * @param source The source to use for all generated ProtocolCommandEvents. - ***/ - public ProtocolCommandSupport(Object source) { - __listeners = new ListenerList(); - __source = source; - } - - /*** - * Fires a ProtocolCommandEvent signalling the sending of a command to all - * registered listeners, invoking their - * {@link ProtocolCommandListener#protocolCommandSent protocolCommandSent() } - * methods. - * - * @param command The string representation of the command type sent, not - * including the arguments (e.g., "STAT" or "GET"). - * @param message The entire command string verbatim as sent to the server, - * including all arguments. - ***/ - public void fireCommandSent(String command, String message) { - ProtocolCommandEvent event; - - event = new ProtocolCommandEvent(__source, command, message); - - for (EventListener listener : __listeners) { - ((ProtocolCommandListener) listener).protocolCommandSent(event); - } - } - - /*** - * Fires a ProtocolCommandEvent signalling the reception of a command reply - * to all registered listeners, invoking their - * {@link ProtocolCommandListener#protocolReplyReceived protocolReplyReceived() } - * methods. - * - * @param replyCode The integer code indicating the natureof the reply. - * This will be the protocol integer value for protocols - * that use integer reply codes, or the reply class constant - * corresponding to the reply for protocols like POP3 that use - * strings like OK rather than integer codes (i.e., POP3Repy.OK). - * @param message The entire reply as received from the server. - ***/ - public void fireReplyReceived(int replyCode, String message) { - ProtocolCommandEvent event; - event = new ProtocolCommandEvent(__source, replyCode, message); - - for (EventListener listener : __listeners) { - ((ProtocolCommandListener) listener).protocolReplyReceived(event); - } - } - - /*** - * Adds a ProtocolCommandListener. - * - * @param listener The ProtocolCommandListener to add. - ***/ - public void addProtocolCommandListener(ProtocolCommandListener listener) { - __listeners.addListener(listener); - } - - /*** - * Removes a ProtocolCommandListener. - * - * @param listener The ProtocolCommandListener to remove. - ***/ - public void removeProtocolCommandListener(ProtocolCommandListener listener) { - __listeners.removeListener(listener); - } - - /*** - * Returns the number of ProtocolCommandListeners currently registered. - * - * @return The number of ProtocolCommandListeners currently registered. - ***/ - public int getListenerCount() { - return __listeners.getListenerCount(); - } -} - diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/SocketClient.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/SocketClient.java deleted file mode 100644 index 0ac183a7..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/SocketClient.java +++ /dev/null @@ -1,869 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net; - -import java.io.Closeable; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.net.Socket; -import java.net.SocketException; -import java.nio.charset.Charset; - -import javax.net.ServerSocketFactory; -import javax.net.SocketFactory; - -/** - * The SocketClient provides the basic operations that are required of - * client objects accessing sockets. It is meant to be - * subclassed to avoid having to rewrite the same code over and over again - * to open a socket, close a socket, set timeouts, etc. Of special note - * is the {@link #setSocketFactory setSocketFactory } - * method, which allows you to control the type of Socket the SocketClient - * creates for initiating network connections. This is especially useful - * for adding SSL or proxy support as well as better support for applets. For - * example, you could create a - * {@link SocketFactory} that - * requests browser security capabilities before creating a socket. - * All classes derived from SocketClient should use the - * {@link #_socketFactory_ _socketFactory_ } member variable to - * create Socket and ServerSocket instances rather than instantiating - * them by directly invoking a constructor. By honoring this contract - * you guarantee that a user will always be able to provide his own - * Socket implementations by substituting his own SocketFactory. - * - * @see SocketFactory - */ -public abstract class SocketClient { - /** - * The end of line character sequence used by most IETF protocols. That - * is a carriage return followed by a newline: "\r\n" - */ - public static final String NETASCII_EOL = "\r\n"; - - /** The default SocketFactory shared by all SocketClient instances. */ - private static final SocketFactory __DEFAULT_SOCKET_FACTORY = SocketFactory.getDefault(); - - /** The default {@link ServerSocketFactory} */ - private static final ServerSocketFactory __DEFAULT_SERVER_SOCKET_FACTORY = - ServerSocketFactory.getDefault(); - - /** - * A ProtocolCommandSupport object used to manage the registering of - * ProtocolCommandListeners and the firing of ProtocolCommandEvents. - */ - private ProtocolCommandSupport __commandSupport; - - /** The timeout to use after opening a socket. */ - protected int _timeout_; - - /** The socket used for the connection. */ - protected Socket _socket_; - - /** The hostname used for the connection (null = no hostname supplied). */ - protected String _hostname_; - - /** The default port the client should connect to. */ - protected int _defaultPort_; - - /** The socket's InputStream. */ - protected InputStream _input_; - - /** The socket's OutputStream. */ - protected OutputStream _output_; - - /** The socket's SocketFactory. */ - protected SocketFactory _socketFactory_; - - /** The socket's ServerSocket Factory. */ - protected ServerSocketFactory _serverSocketFactory_; - - /** The socket's connect timeout (0 = infinite timeout) */ - private static final int DEFAULT_CONNECT_TIMEOUT = 0; - protected int connectTimeout = DEFAULT_CONNECT_TIMEOUT; - - /** Hint for SO_RCVBUF size */ - private int receiveBufferSize = -1; - - /** Hint for SO_SNDBUF size */ - private int sendBufferSize = -1; - - /** The proxy to use when connecting. */ - private Proxy connProxy; - - /** - * Charset to use for byte IO. - */ - private Charset charset = Charset.defaultCharset(); - - /** - * Default constructor for SocketClient. Initializes - * _socket_ to null, _timeout_ to 0, _defaultPort to 0, - * _isConnected_ to false, charset to {@code Charset.defaultCharset()} - * and _socketFactory_ to a shared instance of - * {@link DefaultSocketFactory}. - */ - public SocketClient() { - _socket_ = null; - _hostname_ = null; - _input_ = null; - _output_ = null; - _timeout_ = 0; - _defaultPort_ = 0; - _socketFactory_ = __DEFAULT_SOCKET_FACTORY; - _serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY; - } - - /** - * Because there are so many connect() methods, the _connectAction_() - * method is provided as a means of performing some action immediately - * after establishing a connection, rather than reimplementing all - * of the connect() methods. The last action performed by every - * connect() method after opening a socket is to call this method. - *

- * This method sets the timeout on the just opened socket to the default - * timeout set by {@link #setDefaultTimeout setDefaultTimeout() }, - * sets _input_ and _output_ to the socket's InputStream and OutputStream - * respectively, and sets _isConnected_ to true. - *

- * Subclasses overriding this method should start by calling - * super._connectAction_() first to ensure the - * initialization of the aforementioned protected variables. - * - * @throws IOException (SocketException) if a problem occurs with the socket - */ - protected void _connectAction_() throws IOException { - _socket_.setSoTimeout(_timeout_); - _input_ = _socket_.getInputStream(); - _output_ = _socket_.getOutputStream(); - } - - /** - * Opens a Socket connected to a remote host at the specified port and - * originating from the current host at a system assigned port. - * Before returning, {@link #_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * - * @param host The remote host. - * @param port The port to connect to on the remote host. - * @throws SocketException If the socket timeout could not be set. - * @throws IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - */ - public void connect(InetAddress host, int port) throws SocketException, IOException { - _hostname_ = null; - _connect(host, port, null, -1); - } - - /** - * Opens a Socket connected to a remote host at the specified port and - * originating from the current host at a system assigned port. - * Before returning, {@link #_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * - * @param hostname The name of the remote host. - * @param port The port to connect to on the remote host. - * @throws SocketException If the socket timeout could not be set. - * @throws IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - * @throws java.net.UnknownHostException If the hostname cannot be resolved. - */ - public void connect(String hostname, int port) throws SocketException, IOException { - _hostname_ = hostname; - _connect(InetAddress.getByName(hostname), port, null, -1); - } - - /** - * Opens a Socket connected to a remote host at the specified port and - * originating from the specified local address and port. - * Before returning, {@link #_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * - * @param host The remote host. - * @param port The port to connect to on the remote host. - * @param localAddr The local address to use. - * @param localPort The local port to use. - * @throws SocketException If the socket timeout could not be set. - * @throws IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - */ - public void connect(InetAddress host, int port, InetAddress localAddr, int localPort) - throws SocketException, IOException { - _hostname_ = null; - _connect(host, port, localAddr, localPort); - } - - // helper method to allow code to be shared with connect(String,...) methods - private void _connect(InetAddress host, int port, InetAddress localAddr, int localPort) - throws SocketException, IOException { - _socket_ = _socketFactory_.createSocket(); - if (receiveBufferSize != -1) { - _socket_.setReceiveBufferSize(receiveBufferSize); - } - if (sendBufferSize != -1) { - _socket_.setSendBufferSize(sendBufferSize); - } - if (localAddr != null) { - _socket_.bind(new InetSocketAddress(localAddr, localPort)); - } - _socket_.connect(new InetSocketAddress(host, port), connectTimeout); - _connectAction_(); - } - - /** - * Opens a Socket connected to a remote host at the specified port and - * originating from the specified local address and port. - * Before returning, {@link #_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * - * @param hostname The name of the remote host. - * @param port The port to connect to on the remote host. - * @param localAddr The local address to use. - * @param localPort The local port to use. - * @throws SocketException If the socket timeout could not be set. - * @throws IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - * @throws java.net.UnknownHostException If the hostname cannot be resolved. - */ - public void connect(String hostname, int port, InetAddress localAddr, int localPort) - throws SocketException, IOException { - _hostname_ = hostname; - _connect(InetAddress.getByName(hostname), port, localAddr, localPort); - } - - /** - * Opens a Socket connected to a remote host at the current default port - * and originating from the current host at a system assigned port. - * Before returning, {@link #_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * - * @param host The remote host. - * @throws SocketException If the socket timeout could not be set. - * @throws IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - */ - public void connect(InetAddress host) throws SocketException, IOException { - _hostname_ = null; - connect(host, _defaultPort_); - } - - /** - * Opens a Socket connected to a remote host at the current default - * port and originating from the current host at a system assigned port. - * Before returning, {@link #_connectAction_ _connectAction_() } - * is called to perform connection initialization actions. - *

- * - * @param hostname The name of the remote host. - * @throws SocketException If the socket timeout could not be set. - * @throws IOException If the socket could not be opened. In most - * cases you will only want to catch IOException since SocketException is - * derived from it. - * @throws java.net.UnknownHostException If the hostname cannot be resolved. - */ - public void connect(String hostname) throws SocketException, IOException { - connect(hostname, _defaultPort_); - } - - /** - * Disconnects the socket connection. - * You should call this method after you've finished using the class - * instance and also before you call - * {@link #connect connect() } - * again. _isConnected_ is set to false, _socket_ is set to null, - * _input_ is set to null, and _output_ is set to null. - *

- * - * @throws IOException If there is an error closing the socket. - */ - public void disconnect() throws IOException { - closeQuietly(_socket_); - closeQuietly(_input_); - closeQuietly(_output_); - _socket_ = null; - _hostname_ = null; - _input_ = null; - _output_ = null; - } - - private void closeQuietly(Socket socket) { - if (socket != null) { - try { - socket.close(); - } catch (IOException e) { - // Ignored - } - } - } - - private void closeQuietly(Closeable close) { - if (close != null) { - try { - close.close(); - } catch (IOException e) { - // Ignored - } - } - } - - /** - * Returns true if the client is currently connected to a server. - *

- * Delegates to {@link Socket#isConnected()} - * - * @return True if the client is currently connected to a server, - * false otherwise. - */ - public boolean isConnected() { - if (_socket_ == null) { - return false; - } - - return _socket_.isConnected(); - } - - /** - * Make various checks on the socket to test if it is available for use. - * Note that the only sure test is to use it, but these checks may help - * in some cases. - * - * @return {@code true} if the socket appears to be available for use - * @see NET-350 - * @since 3.0 - */ - public boolean isAvailable() { - if (isConnected()) { - try { - if (_socket_.getInetAddress() == null) { - return false; - } - if (_socket_.getPort() == 0) { - return false; - } - if (_socket_.getRemoteSocketAddress() == null) { - return false; - } - if (_socket_.isClosed()) { - return false; - } - /* these aren't exact checks (a Socket can be half-open), - but since we usually require two-way data transfer, - we check these here too: */ - if (_socket_.isInputShutdown()) { - return false; - } - if (_socket_.isOutputShutdown()) { - return false; - } - /* ignore the result, catch exceptions: */ - _socket_.getInputStream(); - _socket_.getOutputStream(); - } catch (IOException ioex) { - return false; - } - return true; - } else { - return false; - } - } - - /** - * Sets the default port the SocketClient should connect to when a port - * is not specified. The {@link #_defaultPort_ _defaultPort_ } - * variable stores this value. If never set, the default port is equal - * to zero. - *

- * - * @param port The default port to set. - */ - public void setDefaultPort(int port) { - _defaultPort_ = port; - } - - /** - * Returns the current value of the default port (stored in - * {@link #_defaultPort_ _defaultPort_ }). - *

- * - * @return The current value of the default port. - */ - public int getDefaultPort() { - return _defaultPort_; - } - - /** - * Set the default timeout in milliseconds to use when opening a socket. - * This value is only used previous to a call to - * {@link #connect connect()} - * and should not be confused with {@link #setSoTimeout setSoTimeout()} - * which operates on an the currently opened socket. _timeout_ contains - * the new timeout value. - *

- * - * @param timeout The timeout in milliseconds to use for the socket - * connection. - */ - public void setDefaultTimeout(int timeout) { - _timeout_ = timeout; - } - - /** - * Returns the default timeout in milliseconds that is used when - * opening a socket. - *

- * - * @return The default timeout in milliseconds that is used when - * opening a socket. - */ - public int getDefaultTimeout() { - return _timeout_; - } - - /** - * Set the timeout in milliseconds of a currently open connection. - * Only call this method after a connection has been opened - * by {@link #connect connect()}. - *

- * To set the initial timeout, use {@link #setDefaultTimeout(int)} instead. - * - * @param timeout The timeout in milliseconds to use for the currently - * open socket connection. - * @throws SocketException If the operation fails. - * @throws NullPointerException if the socket is not currently open - */ - public void setSoTimeout(int timeout) throws SocketException { - _socket_.setSoTimeout(timeout); - } - - /** - * Set the underlying socket send buffer size. - *

- * - * @param size The size of the buffer in bytes. - * @throws SocketException never thrown, but subclasses might want to do so - * @since 2.0 - */ - public void setSendBufferSize(int size) throws SocketException { - sendBufferSize = size; - } - - /** - * Get the current sendBuffer size - * - * @return the size, or -1 if not initialised - * @since 3.0 - */ - protected int getSendBufferSize() { - return sendBufferSize; - } - - /** - * Sets the underlying socket receive buffer size. - *

- * - * @param size The size of the buffer in bytes. - * @throws SocketException never (but subclasses may wish to do so) - * @since 2.0 - */ - public void setReceiveBufferSize(int size) throws SocketException { - receiveBufferSize = size; - } - - /** - * Get the current receivedBuffer size - * - * @return the size, or -1 if not initialised - * @since 3.0 - */ - protected int getReceiveBufferSize() { - return receiveBufferSize; - } - - /** - * Returns the timeout in milliseconds of the currently opened socket. - *

- * - * @return The timeout in milliseconds of the currently opened socket. - * @throws SocketException If the operation fails. - * @throws NullPointerException if the socket is not currently open - */ - public int getSoTimeout() throws SocketException { - return _socket_.getSoTimeout(); - } - - /** - * Enables or disables the Nagle's algorithm (TCP_NODELAY) on the - * currently opened socket. - *

- * - * @param on True if Nagle's algorithm is to be enabled, false if not. - * @throws SocketException If the operation fails. - * @throws NullPointerException if the socket is not currently open - */ - public void setTcpNoDelay(boolean on) throws SocketException { - _socket_.setTcpNoDelay(on); - } - - /** - * Returns true if Nagle's algorithm is enabled on the currently opened - * socket. - *

- * - * @return True if Nagle's algorithm is enabled on the currently opened - * socket, false otherwise. - * @throws SocketException If the operation fails. - * @throws NullPointerException if the socket is not currently open - */ - public boolean getTcpNoDelay() throws SocketException { - return _socket_.getTcpNoDelay(); - } - - /** - * Sets the SO_KEEPALIVE flag on the currently opened socket. - * - * From the Javadocs, the default keepalive time is 2 hours (although this is - * implementation dependent). It looks as though the Windows WSA sockets implementation - * allows a specific keepalive value to be set, although this seems not to be the case on - * other systems. - * - * @param keepAlive If true, keepAlive is turned on - * @throws SocketException if there is a problem with the socket - * @throws NullPointerException if the socket is not currently open - * @since 2.2 - */ - public void setKeepAlive(boolean keepAlive) throws SocketException { - _socket_.setKeepAlive(keepAlive); - } - - /** - * Returns the current value of the SO_KEEPALIVE flag on the currently opened socket. - * Delegates to {@link Socket#getKeepAlive()} - * - * @return True if SO_KEEPALIVE is enabled. - * @throws SocketException if there is a problem with the socket - * @throws NullPointerException if the socket is not currently open - * @since 2.2 - */ - public boolean getKeepAlive() throws SocketException { - return _socket_.getKeepAlive(); - } - - /** - * Sets the SO_LINGER timeout on the currently opened socket. - *

- * - * @param on True if linger is to be enabled, false if not. - * @param val The linger timeout (in hundredths of a second?) - * @throws SocketException If the operation fails. - * @throws NullPointerException if the socket is not currently open - */ - public void setSoLinger(boolean on, int val) throws SocketException { - _socket_.setSoLinger(on, val); - } - - /** - * Returns the current SO_LINGER timeout of the currently opened socket. - *

- * - * @return The current SO_LINGER timeout. If SO_LINGER is disabled returns - * -1. - * @throws SocketException If the operation fails. - * @throws NullPointerException if the socket is not currently open - */ - public int getSoLinger() throws SocketException { - return _socket_.getSoLinger(); - } - - /** - * Returns the port number of the open socket on the local host used - * for the connection. - * Delegates to {@link Socket#getLocalPort()} - *

- * - * @return The port number of the open socket on the local host used - * for the connection. - * @throws NullPointerException if the socket is not currently open - */ - public int getLocalPort() { - return _socket_.getLocalPort(); - } - - /** - * Returns the local address to which the client's socket is bound. - * Delegates to {@link Socket#getLocalAddress()} - *

- * - * @return The local address to which the client's socket is bound. - * @throws NullPointerException if the socket is not currently open - */ - public InetAddress getLocalAddress() { - return _socket_.getLocalAddress(); - } - - /** - * Returns the port number of the remote host to which the client is - * connected. - * Delegates to {@link Socket#getPort()} - *

- * - * @return The port number of the remote host to which the client is - * connected. - * @throws NullPointerException if the socket is not currently open - */ - public int getRemotePort() { - return _socket_.getPort(); - } - - /** - * @return The remote address to which the client is connected. - * Delegates to {@link Socket#getInetAddress()} - * @throws NullPointerException if the socket is not currently open - */ - public InetAddress getRemoteAddress() { - return _socket_.getInetAddress(); - } - - /** - * Verifies that the remote end of the given socket is connected to the - * the same host that the SocketClient is currently connected to. This - * is useful for doing a quick security check when a client needs to - * accept a connection from a server, such as an FTP data connection or - * a BSD R command standard error stream. - *

- * - * @param socket the item to check against - * @return True if the remote hosts are the same, false if not. - */ - public boolean verifyRemote(Socket socket) { - InetAddress host1, host2; - - host1 = socket.getInetAddress(); - host2 = getRemoteAddress(); - - return host1.equals(host2); - } - - /** - * Sets the SocketFactory used by the SocketClient to open socket - * connections. If the factory value is null, then a default - * factory is used (only do this to reset the factory after having - * previously altered it). - * Any proxy setting is discarded. - *

- * - * @param factory The new SocketFactory the SocketClient should use. - */ - public void setSocketFactory(SocketFactory factory) { - if (factory == null) { - _socketFactory_ = __DEFAULT_SOCKET_FACTORY; - } else { - _socketFactory_ = factory; - } - // re-setting the socket factory makes the proxy setting useless, - // so set the field to null so that getProxy() doesn't return a - // Proxy that we're actually not using. - connProxy = null; - } - - /** - * Sets the ServerSocketFactory used by the SocketClient to open ServerSocket - * connections. If the factory value is null, then a default - * factory is used (only do this to reset the factory after having - * previously altered it). - *

- * - * @param factory The new ServerSocketFactory the SocketClient should use. - * @since 2.0 - */ - public void setServerSocketFactory(ServerSocketFactory factory) { - if (factory == null) { - _serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY; - } else { - _serverSocketFactory_ = factory; - } - } - - /** - * Sets the connection timeout in milliseconds, which will be passed to the {@link Socket} - * object's - * connect() method. - * - * @param connectTimeout The connection timeout to use (in ms) - * @since 2.0 - */ - public void setConnectTimeout(int connectTimeout) { - this.connectTimeout = connectTimeout; - } - - /** - * Get the underlying socket connection timeout. - * - * @return timeout (in ms) - * @since 2.0 - */ - public int getConnectTimeout() { - return connectTimeout; - } - - /** - * Get the underlying {@link ServerSocketFactory} - * - * @return The server socket factory - * @since 2.2 - */ - public ServerSocketFactory getServerSocketFactory() { - return _serverSocketFactory_; - } - - /** - * Adds a ProtocolCommandListener. - * - * @param listener The ProtocolCommandListener to add. - * @since 3.0 - */ - public void addProtocolCommandListener(ProtocolCommandListener listener) { - getCommandSupport().addProtocolCommandListener(listener); - } - - /** - * Removes a ProtocolCommandListener. - * - * @param listener The ProtocolCommandListener to remove. - * @since 3.0 - */ - public void removeProtocolCommandListener(ProtocolCommandListener listener) { - getCommandSupport().removeProtocolCommandListener(listener); - } - - /** - * If there are any listeners, send them the reply details. - * - * @param replyCode the code extracted from the reply - * @param reply the full reply text - * @since 3.0 - */ - protected void fireReplyReceived(int replyCode, String reply) { - if (getCommandSupport().getListenerCount() > 0) { - getCommandSupport().fireReplyReceived(replyCode, reply); - } - } - - /** - * If there are any listeners, send them the command details. - * - * @param command the command name - * @param message the complete message, including command name - * @since 3.0 - */ - protected void fireCommandSent(String command, String message) { - if (getCommandSupport().getListenerCount() > 0) { - getCommandSupport().fireCommandSent(command, message); - } - } - - /** - * Create the CommandSupport instance if required - */ - protected void createCommandSupport() { - __commandSupport = new ProtocolCommandSupport(this); - } - - /** - * Subclasses can override this if they need to provide their own - * instance field for backwards compatibilty. - * - * @return the CommandSupport instance, may be {@code null} - * @since 3.0 - */ - protected ProtocolCommandSupport getCommandSupport() { - return __commandSupport; - } - - /** - * Sets the proxy for use with all the connections. - * The proxy is used for connections established after the - * call to this method. - * - * @param proxy the new proxy for connections. - * @since 3.2 - */ - public void setProxy(Proxy proxy) { - setSocketFactory(new DefaultSocketFactory(proxy)); - connProxy = proxy; - } - - /** - * Gets the proxy for use with all the connections. - * - * @return the current proxy for connections. - */ - public Proxy getProxy() { - return connProxy; - } - - /** - * Gets the charset name. - * - * @return the charset. - * @since 3.3 - * @deprecated Since the code now requires Java 1.6 as a mininmum - */ - @Deprecated public String getCharsetName() { - return charset.name(); - } - - /** - * Gets the charset. - * - * @return the charset. - * @since 3.3 - */ - public Charset getCharset() { - return charset; - } - - /** - * Sets the charset. - * - * @param charset the charset. - * @since 3.3 - */ - public void setCharset(Charset charset) { - this.charset = charset; - } - - /* - * N.B. Fields cannot be pulled up into a super-class without breaking binary compatibility, - * so the abstract method is needed to pass the instance to the methods which were moved here. - */ -} - - diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/Configurable.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/Configurable.java deleted file mode 100644 index b0361f80..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/Configurable.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -/** - * This interface adds the aspect of configurability by means of - * a supplied FTPClientConfig object to other classes in the - * system, especially listing parsers. - */ -public interface Configurable { - - /** - * @param config the object containing the configuration data - * @throws IllegalArgumentException if the elements of the - * config are somehow inadequate to configure the - * Configurable object. - */ - public void configure(FTPClientConfig config); -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTP.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTP.java deleted file mode 100644 index 12a99b15..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTP.java +++ /dev/null @@ -1,1777 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.SocketException; -import java.net.SocketTimeoutException; -import java.util.ArrayList; - -import aria.apache.commons.net.MalformedServerReplyException; -import aria.apache.commons.net.ProtocolCommandSupport; -import aria.apache.commons.net.SocketClient; -import aria.apache.commons.net.io.CRLFLineReader; - -/*** - * FTP provides the basic the functionality necessary to implement your - * own FTP client. It extends SocketClient since - * extending TelnetClient was causing unwanted behavior (like connections - * that did not time out properly). - *

- * To derive the full benefits of the FTP class requires some knowledge - * of the FTP protocol defined in RFC 959. However, there is no reason - * why you should have to use the FTP class. The - * {@link FTPClient} class, - * derived from FTP, - * implements all the functionality required of an FTP client. The - * FTP class is made public to provide access to various FTP constants - * and to make it easier for adventurous programmers (or those with - * special needs) to interact with the FTP protocol and implement their - * own clients. A set of methods with names corresponding to the FTP - * command names are provided to facilitate this interaction. - *

- * You should keep in mind that the FTP server may choose to prematurely - * close a connection if the client has been idle for longer than a - * given time period (usually 900 seconds). The FTP class will detect a - * premature FTP server connection closing when it receives a - * {@link FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } - * response to a command. - * When that occurs, the FTP class method encountering that reply will throw - * an {@link FTPConnectionClosedException} - * . FTPConectionClosedException - * is a subclass of IOException and therefore need not be - * caught separately, but if you are going to catch it separately, its - * catch block must appear before the more general IOException - * catch block. When you encounter an - * {@link FTPConnectionClosedException} - * , you must disconnect the connection with - * {@link #disconnect disconnect() } to properly clean up the - * system resources used by FTP. Before disconnecting, you may check the - * last reply code and text with - * {@link #getReplyCode getReplyCode }, - * {@link #getReplyString getReplyString }, - * and {@link #getReplyStrings getReplyStrings}. - * You may avoid server disconnections while the client is idle by - * periodicaly sending NOOP commands to the server. - *

- * Rather than list it separately for each method, we mention here that - * every method communicating with the server and throwing an IOException - * can also throw a - * {@link MalformedServerReplyException} - * , which is a subclass - * of IOException. A MalformedServerReplyException will be thrown when - * the reply received from the server deviates enough from the protocol - * specification that it cannot be interpreted in a useful manner despite - * attempts to be as lenient as possible. - * - * @see FTPClient - * @see FTPConnectionClosedException - * @see MalformedServerReplyException - * @version $Id: FTP.java 1782546 2017-02-11 00:05:41Z sebb $ - ***/ - -public class FTP extends SocketClient { - /*** The default FTP data port (20). ***/ - public static final int DEFAULT_DATA_PORT = 20; - /*** The default FTP control port (21). ***/ - public static final int DEFAULT_PORT = 21; - - /*** - * A constant used to indicate the file(s) being transferred should - * be treated as ASCII. This is the default file type. All constants - * ending in FILE_TYPE are used to indicate file types. - ***/ - public static final int ASCII_FILE_TYPE = 0; - - /*** - * A constant used to indicate the file(s) being transferred should - * be treated as EBCDIC. Note however that there are several different - * EBCDIC formats. All constants ending in FILE_TYPE - * are used to indicate file types. - ***/ - public static final int EBCDIC_FILE_TYPE = 1; - - /*** - * A constant used to indicate the file(s) being transferred should - * be treated as a binary image, i.e., no translations should be - * performed. All constants ending in FILE_TYPE are used to - * indicate file types. - ***/ - public static final int BINARY_FILE_TYPE = 2; - - /*** - * A constant used to indicate the file(s) being transferred should - * be treated as a local type. All constants ending in - * FILE_TYPE are used to indicate file types. - ***/ - public static final int LOCAL_FILE_TYPE = 3; - - /*** - * A constant used for text files to indicate a non-print text format. - * This is the default format. - * All constants ending in TEXT_FORMAT are used to indicate - * text formatting for text transfers (both ASCII and EBCDIC). - ***/ - public static final int NON_PRINT_TEXT_FORMAT = 4; - - /*** - * A constant used to indicate a text file contains format vertical format - * control characters. - * All constants ending in TEXT_FORMAT are used to indicate - * text formatting for text transfers (both ASCII and EBCDIC). - ***/ - public static final int TELNET_TEXT_FORMAT = 5; - - /*** - * A constant used to indicate a text file contains ASA vertical format - * control characters. - * All constants ending in TEXT_FORMAT are used to indicate - * text formatting for text transfers (both ASCII and EBCDIC). - ***/ - public static final int CARRIAGE_CONTROL_TEXT_FORMAT = 6; - - /*** - * A constant used to indicate a file is to be treated as a continuous - * sequence of bytes. This is the default structure. All constants ending - * in _STRUCTURE are used to indicate file structure for - * file transfers. - ***/ - public static final int FILE_STRUCTURE = 7; - - /*** - * A constant used to indicate a file is to be treated as a sequence - * of records. All constants ending in _STRUCTURE - * are used to indicate file structure for file transfers. - ***/ - public static final int RECORD_STRUCTURE = 8; - - /*** - * A constant used to indicate a file is to be treated as a set of - * independent indexed pages. All constants ending in - * _STRUCTURE are used to indicate file structure for file - * transfers. - ***/ - public static final int PAGE_STRUCTURE = 9; - - /*** - * A constant used to indicate a file is to be transferred as a stream - * of bytes. This is the default transfer mode. All constants ending - * in TRANSFER_MODE are used to indicate file transfer - * modes. - ***/ - public static final int STREAM_TRANSFER_MODE = 10; - - /*** - * A constant used to indicate a file is to be transferred as a series - * of blocks. All constants ending in TRANSFER_MODE are used - * to indicate file transfer modes. - ***/ - public static final int BLOCK_TRANSFER_MODE = 11; - - /*** - * A constant used to indicate a file is to be transferred as FTP - * compressed data. All constants ending in TRANSFER_MODE - * are used to indicate file transfer modes. - ***/ - public static final int COMPRESSED_TRANSFER_MODE = 12; - - // We have to ensure that the protocol communication is in ASCII - // but we use ISO-8859-1 just in case 8-bit characters cross - // the wire. - /** - * The default character encoding used for communicating over an - * FTP control connection. The default encoding is an - * ASCII-compatible encoding. Some FTP servers expect other - * encodings. You can change the encoding used by an FTP instance - * with {@link #setControlEncoding setControlEncoding}. - */ - public static final String DEFAULT_CONTROL_ENCODING = "ISO-8859-1"; - - /** Length of the FTP reply code (3 alphanumerics) */ - public static final int REPLY_CODE_LEN = 3; - - private static final String __modes = "AEILNTCFRPSBC"; - - protected int _replyCode; - protected ArrayList _replyLines; - protected boolean _newReplyString; - protected String _replyString; - protected String _controlEncoding; - - /** - * A ProtocolCommandSupport object used to manage the registering of - * ProtocolCommandListeners and te firing of ProtocolCommandEvents. - */ - protected ProtocolCommandSupport _commandSupport_; - - /** - * This is used to signal whether a block of multiline responses beginning - * with xxx must be terminated by the same numeric code xxx - * See section 4.2 of RFC 959 for details. - */ - protected boolean strictMultilineParsing = false; - - /** - * If this is true, then non-multiline replies must have the format: - * 3 digit code - * If false, then the 3 digit code does not have to be followed by space - * See section 4.2 of RFC 959 for details. - */ - private boolean strictReplyParsing = true; - - /** - * Wraps SocketClient._input_ to facilitate the reading of text - * from the FTP control connection. Do not access the control - * connection via SocketClient._input_. This member starts - * with a null value, is initialized in {@link #_connectAction_}, - * and set to null in {@link #disconnect}. - */ - protected BufferedReader _controlInput_; - - /** - * Wraps SocketClient._output_ to facilitate the writing of text - * to the FTP control connection. Do not access the control - * connection via SocketClient._output_. This member starts - * with a null value, is initialized in {@link #_connectAction_}, - * and set to null in {@link #disconnect}. - */ - protected BufferedWriter _controlOutput_; - - /*** - * The default FTP constructor. Sets the default port to - * DEFAULT_PORT and initializes internal data structures - * for saving FTP reply information. - ***/ - public FTP() { - super(); - setDefaultPort(DEFAULT_PORT); - _replyLines = new ArrayList(); - _newReplyString = false; - _replyString = null; - _controlEncoding = DEFAULT_CONTROL_ENCODING; - _commandSupport_ = new ProtocolCommandSupport(this); - } - - // The RFC-compliant multiline termination check - private boolean __strictCheck(String line, String code) { - return (!(line.startsWith(code) && line.charAt(REPLY_CODE_LEN) == ' ')); - } - - // The strict check is too strong a condition because of non-conforming ftp - // servers like ftp.funet.fi which sent 226 as the last line of a - // 426 multi-line reply in response to ls /. We relax the condition to - // test that the line starts with a digit rather than starting with - // the code. - private boolean __lenientCheck(String line) { - return (!(line.length() > REPLY_CODE_LEN - && line.charAt(REPLY_CODE_LEN) != '-' - && Character.isDigit(line.charAt(0)))); - } - - /** - * Get the reply, and pass it to command listeners - */ - private void __getReply() throws IOException { - __getReply(true); - } - - /** - * Get the reply, but don't pass it to command listeners. - * Used for keep-alive processing only. - * - * @throws IOException on error - * @since 3.0 - */ - protected void __getReplyNoReport() throws IOException { - __getReply(false); - } - - private void __getReply(boolean reportReply) throws IOException { - int length; - - _newReplyString = true; - _replyLines.clear(); - - String line = _controlInput_.readLine(); - - if (line == null) { - throw new FTPConnectionClosedException("Connection closed without indication."); - } - - // In case we run into an anomaly we don't want fatal index exceptions - // to be thrown. - length = line.length(); - if (length < REPLY_CODE_LEN) { - throw new MalformedServerReplyException("Truncated server reply: " + line); - } - - String code = null; - try { - code = line.substring(0, REPLY_CODE_LEN); - _replyCode = Integer.parseInt(code); - } catch (NumberFormatException e) { - throw new MalformedServerReplyException( - "Could not parse response code.\nServer Reply: " + line); - } - - _replyLines.add(line); - - // Check the server reply type - if (length > REPLY_CODE_LEN) { - char sep = line.charAt(REPLY_CODE_LEN); - // Get extra lines if message continues. - if (sep == '-') { - do { - line = _controlInput_.readLine(); - - if (line == null) { - throw new FTPConnectionClosedException("Connection closed without indication."); - } - - _replyLines.add(line); - - // The length() check handles problems that could arise from readLine() - // returning too soon after encountering a naked CR or some other - // anomaly. - } while (isStrictMultilineParsing() ? __strictCheck(line, code) : __lenientCheck(line)); - } else if (isStrictReplyParsing()) { - if (length == REPLY_CODE_LEN + 1) { // expecting some text - throw new MalformedServerReplyException("Truncated server reply: '" + line + "'"); - } else if (sep != ' ') { - throw new MalformedServerReplyException("Invalid server reply: '" + line + "'"); - } - } - } else if (isStrictReplyParsing()) { - throw new MalformedServerReplyException("Truncated server reply: '" + line + "'"); - } - - if (reportReply) { - fireReplyReceived(_replyCode, getReplyString()); - } - - if (_replyCode == FTPReply.SERVICE_NOT_AVAILABLE) { - throw new FTPConnectionClosedException( - "FTP response 421 received. Server closed connection."); - } - } - - /** - * Initiates control connections and gets initial reply. - * Initializes {@link #_controlInput_} and {@link #_controlOutput_}. - */ - @Override protected void _connectAction_() throws IOException { - _connectAction_(null); - } - - /** - * Initiates control connections and gets initial reply. - * Initializes {@link #_controlInput_} and {@link #_controlOutput_}. - * - * @param socketIsReader the reader to reuse (if non-null) - * @throws IOException on error - * @since 3.4 - */ - protected void _connectAction_(Reader socketIsReader) throws IOException { - super._connectAction_(); // sets up _input_ and _output_ - if (socketIsReader == null) { - _controlInput_ = new CRLFLineReader(new InputStreamReader(_input_, getControlEncoding())); - } else { - _controlInput_ = new CRLFLineReader(socketIsReader); - } - _controlOutput_ = new BufferedWriter(new OutputStreamWriter(_output_, getControlEncoding())); - if (connectTimeout > 0) { // NET-385 - int original = _socket_.getSoTimeout(); - _socket_.setSoTimeout(connectTimeout); - try { - __getReply(); - // If we received code 120, we have to fetch completion reply. - if (FTPReply.isPositivePreliminary(_replyCode)) { - __getReply(); - } - } catch (SocketTimeoutException e) { - IOException ioe = new IOException("Timed out waiting for initial connect reply"); - ioe.initCause(e); - throw ioe; - } finally { - _socket_.setSoTimeout(original); - } - } else { - __getReply(); - // If we received code 120, we have to fetch completion reply. - if (FTPReply.isPositivePreliminary(_replyCode)) { - __getReply(); - } - } - } - - /** - * Saves the character encoding to be used by the FTP control connection. - * Some FTP servers require that commands be issued in a non-ASCII - * encoding like UTF-8 so that filenames with multi-byte character - * representations (e.g, Big 8) can be specified. - *

- * Please note that this has to be set before the connection is established. - * - * @param encoding The new character encoding for the control connection. - */ - public void setControlEncoding(String encoding) { - _controlEncoding = encoding; - } - - /** - * @return The character encoding used to communicate over the - * control connection. - */ - public String getControlEncoding() { - return _controlEncoding; - } - - /*** - * Closes the control connection to the FTP server and sets to null - * some internal data so that the memory may be reclaimed by the - * garbage collector. The reply text and code information from the - * last command is voided so that the memory it used may be reclaimed. - * Also sets {@link #_controlInput_} and {@link #_controlOutput_} to null. - * - * @throws IOException If an error occurs while disconnecting. - ***/ - @Override public void disconnect() throws IOException { - super.disconnect(); - _controlInput_ = null; - _controlOutput_ = null; - _newReplyString = false; - _replyString = null; - } - - /*** - * Sends an FTP command to the server, waits for a reply and returns the - * numerical response code. After invocation, for more detailed - * information, the actual reply text can be accessed by calling - * {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - * - * @param command The text representation of the FTP command to send. - * @param args The arguments to the FTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return The integer value of the FTP reply code returned by the server - * in response to the command. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int sendCommand(String command, String args) throws IOException { - if (_controlOutput_ == null) { - throw new IOException("Connection is not open"); - } - - final String message = __buildMessage(command, args); - - __send(message); - - fireCommandSent(command, message); - - __getReply(); - return _replyCode; - } - - private String __buildMessage(String command, String args) { - final StringBuilder __commandBuffer = new StringBuilder(); - - __commandBuffer.append(command); - - if (args != null) { - __commandBuffer.append(' '); - __commandBuffer.append(args); - } - __commandBuffer.append(SocketClient.NETASCII_EOL); - return __commandBuffer.toString(); - } - - private void __send(String message) - throws IOException, FTPConnectionClosedException, SocketException { - try { - _controlOutput_.write(message); - _controlOutput_.flush(); - } catch (SocketException e) { - if (!isConnected()) { - throw new FTPConnectionClosedException("Connection unexpectedly closed."); - } else { - throw e; - } - } - } - - /** - * Send a noop and get the reply without reporting to the command listener. - * Intended for use with keep-alive. - * - * @throws IOException on error - * @since 3.0 - */ - protected void __noop() throws IOException { - String msg = __buildMessage(FTPCmd.NOOP.getCommand(), null); - __send(msg); - __getReplyNoReport(); // This may timeout - } - - /*** - * Sends an FTP command to the server, waits for a reply and returns the - * numerical response code. After invocation, for more detailed - * information, the actual reply text can be accessed by calling - * {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - * - * @param command The FTPCommand constant corresponding to the FTP command - * to send. - * @param args The arguments to the FTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return The integer value of the FTP reply code returned by the server - * in response to the command. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @deprecated (3.3) Use {@link #sendCommand(FTPCmd, String)} instead - ***/ - @Deprecated public int sendCommand(int command, String args) throws IOException { - return sendCommand(FTPCommand.getCommand(command), args); - } - - /** - * Sends an FTP command to the server, waits for a reply and returns the - * numerical response code. After invocation, for more detailed - * information, the actual reply text can be accessed by calling - * {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - * - * @param command The FTPCmd enum corresponding to the FTP command - * to send. - * @return The integer value of the FTP reply code returned by the server - * in response to the command. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 3.3 - */ - public int sendCommand(FTPCmd command) throws IOException { - return sendCommand(command, null); - } - - /** - * Sends an FTP command to the server, waits for a reply and returns the - * numerical response code. After invocation, for more detailed - * information, the actual reply text can be accessed by calling - * {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - * - * @param command The FTPCmd enum corresponding to the FTP command - * to send. - * @param args The arguments to the FTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return The integer value of the FTP reply code returned by the server - * in response to the command. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 3.3 - */ - public int sendCommand(FTPCmd command, String args) throws IOException { - return sendCommand(command.getCommand(), args); - } - - /*** - * Sends an FTP command with no arguments to the server, waits for a - * reply and returns the numerical response code. After invocation, for - * more detailed information, the actual reply text can be accessed by - * calling {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - * - * @param command The text representation of the FTP command to send. - * @return The integer value of the FTP reply code returned by the server - * in response to the command. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int sendCommand(String command) throws IOException { - return sendCommand(command, null); - } - - /*** - * Sends an FTP command with no arguments to the server, waits for a - * reply and returns the numerical response code. After invocation, for - * more detailed information, the actual reply text can be accessed by - * calling {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. - * - * @param command The FTPCommand constant corresponding to the FTP command - * to send. - * @return The integer value of the FTP reply code returned by the server - * in response to the command. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int sendCommand(int command) throws IOException { - return sendCommand(command, null); - } - - /*** - * Returns the integer value of the reply code of the last FTP reply. - * You will usually only use this method after you connect to the - * FTP server to check that the connection was successful since - * connect is of type void. - * - * @return The integer value of the reply code of the last FTP reply. - ***/ - public int getReplyCode() { - return _replyCode; - } - - /*** - * Fetches a reply from the FTP server and returns the integer reply - * code. After calling this method, the actual reply text can be accessed - * from either calling {@link #getReplyString getReplyString } or - * {@link #getReplyStrings getReplyStrings }. Only use this - * method if you are implementing your own FTP client or if you need to - * fetch a secondary response from the FTP server. - * - * @return The integer value of the reply code of the fetched FTP reply. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while receiving the - * server reply. - ***/ - public int getReply() throws IOException { - __getReply(); - return _replyCode; - } - - /*** - * Returns the lines of text from the last FTP server response as an array - * of strings, one entry per line. The end of line markers of each are - * stripped from each line. - * - * @return The lines of text from the last FTP response as an array. - ***/ - public String[] getReplyStrings() { - return _replyLines.toArray(new String[_replyLines.size()]); - } - - /*** - * Returns the entire text of the last FTP server response exactly - * as it was received, including all end of line markers in NETASCII - * format. - * - * @return The entire text from the last FTP response as a String. - ***/ - public String getReplyString() { - StringBuilder buffer; - - if (!_newReplyString) { - return _replyString; - } - - buffer = new StringBuilder(256); - - for (String line : _replyLines) { - buffer.append(line); - buffer.append(SocketClient.NETASCII_EOL); - } - - _newReplyString = false; - - return (_replyString = buffer.toString()); - } - - /*** - * A convenience method to send the FTP USER command to the server, - * receive the reply, and return the reply code. - * - * @param username The username to login under. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int user(String username) throws IOException { - return sendCommand(FTPCmd.USER, username); - } - - /** - * A convenience method to send the FTP PASS command to the server, - * receive the reply, and return the reply code. - * - * @param password The plain text password of the username being logged into. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int pass(String password) throws IOException { - return sendCommand(FTPCmd.PASS, password); - } - - /*** - * A convenience method to send the FTP ACCT command to the server, - * receive the reply, and return the reply code. - * - * @param account The account name to access. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int acct(String account) throws IOException { - return sendCommand(FTPCmd.ACCT, account); - } - - /*** - * A convenience method to send the FTP ABOR command to the server, - * receive the reply, and return the reply code. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int abor() throws IOException { - return sendCommand(FTPCmd.ABOR); - } - - /*** - * A convenience method to send the FTP CWD command to the server, - * receive the reply, and return the reply code. - * - * @param directory The new working directory. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int cwd(String directory) throws IOException { - return sendCommand(FTPCmd.CWD, directory); - } - - /*** - * A convenience method to send the FTP CDUP command to the server, - * receive the reply, and return the reply code. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int cdup() throws IOException { - return sendCommand(FTPCmd.CDUP); - } - - /*** - * A convenience method to send the FTP QUIT command to the server, - * receive the reply, and return the reply code. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int quit() throws IOException { - return sendCommand(FTPCmd.QUIT); - } - - /*** - * A convenience method to send the FTP REIN command to the server, - * receive the reply, and return the reply code. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int rein() throws IOException { - return sendCommand(FTPCmd.REIN); - } - - /*** - * A convenience method to send the FTP SMNT command to the server, - * receive the reply, and return the reply code. - * - * @param dir The directory name. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int smnt(String dir) throws IOException { - return sendCommand(FTPCmd.SMNT, dir); - } - - /*** - * A convenience method to send the FTP PORT command to the server, - * receive the reply, and return the reply code. - * - * @param host The host owning the port. - * @param port The new port. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int port(InetAddress host, int port) throws IOException { - int num; - StringBuilder info = new StringBuilder(24); - - info.append(host.getHostAddress().replace('.', ',')); - num = port >>> 8; - info.append(','); - info.append(num); - info.append(','); - num = port & 0xff; - info.append(num); - - return sendCommand(FTPCmd.PORT, info.toString()); - } - - /*** - * A convenience method to send the FTP EPRT command to the server, - * receive the reply, and return the reply code. - * - * Examples: - *

- * - * @see "http://www.faqs.org/rfcs/rfc2428.html" - * - * @param host The host owning the port. - * @param port The new port. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 2.2 - ***/ - public int eprt(InetAddress host, int port) throws IOException { - int num; - StringBuilder info = new StringBuilder(); - String h; - - // If IPv6, trim the zone index - h = host.getHostAddress(); - num = h.indexOf("%"); - if (num > 0) { - h = h.substring(0, num); - } - - info.append("|"); - - if (host instanceof Inet4Address) { - info.append("1"); - } else if (host instanceof Inet6Address) { - info.append("2"); - } - info.append("|"); - info.append(h); - info.append("|"); - info.append(port); - info.append("|"); - - return sendCommand(FTPCmd.EPRT, info.toString()); - } - - /*** - * A convenience method to send the FTP PASV command to the server, - * receive the reply, and return the reply code. Remember, it's up - * to you to interpret the reply string containing the host/port - * information. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int pasv() throws IOException { - return sendCommand(FTPCmd.PASV); - } - - /*** - * A convenience method to send the FTP EPSV command to the server, - * receive the reply, and return the reply code. Remember, it's up - * to you to interpret the reply string containing the host/port - * information. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 2.2 - ***/ - public int epsv() throws IOException { - return sendCommand(FTPCmd.EPSV); - } - - /** - * A convenience method to send the FTP TYPE command for text files - * to the server, receive the reply, and return the reply code. - * - * @param fileType The type of the file (one of the FILE_TYPE - * constants). - * @param formatOrByteSize The format of the file (one of the - * _FORMAT constants. In the case of - * LOCAL_FILE_TYPE, the byte size. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int type(int fileType, int formatOrByteSize) throws IOException { - StringBuilder arg = new StringBuilder(); - - arg.append(__modes.charAt(fileType)); - arg.append(' '); - if (fileType == LOCAL_FILE_TYPE) { - arg.append(formatOrByteSize); - } else { - arg.append(__modes.charAt(formatOrByteSize)); - } - - return sendCommand(FTPCmd.TYPE, arg.toString()); - } - - /** - * A convenience method to send the FTP TYPE command to the server, - * receive the reply, and return the reply code. - * - * @param fileType The type of the file (one of the FILE_TYPE - * constants). - * @return The reply code received from the server. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int type(int fileType) throws IOException { - return sendCommand(FTPCmd.TYPE, __modes.substring(fileType, fileType + 1)); - } - - /*** - * A convenience method to send the FTP STRU command to the server, - * receive the reply, and return the reply code. - * - * @param structure The structure of the file (one of the - * _STRUCTURE constants). - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int stru(int structure) throws IOException { - return sendCommand(FTPCmd.STRU, __modes.substring(structure, structure + 1)); - } - - /*** - * A convenience method to send the FTP MODE command to the server, - * receive the reply, and return the reply code. - * - * @param mode The transfer mode to use (one of the - * TRANSFER_MODE constants). - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int mode(int mode) throws IOException { - return sendCommand(FTPCmd.MODE, __modes.substring(mode, mode + 1)); - } - - /*** - * A convenience method to send the FTP RETR command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link FTPClient} - * , which will handle all low level details for you. - * - * @param pathname The pathname of the file to retrieve. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int retr(String pathname) throws IOException { - return sendCommand(FTPCmd.RETR, pathname); - } - - /*** - * A convenience method to send the FTP STOR command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link FTPClient} - * , which will handle all low level details for you. - * - * @param pathname The pathname to use for the file when stored at - * the remote end of the transfer. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int stor(String pathname) throws IOException { - return sendCommand(FTPCmd.STOR, pathname); - } - - /*** - * A convenience method to send the FTP STOU command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link FTPClient} - * , which will handle all low level details for you. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int stou() throws IOException { - return sendCommand(FTPCmd.STOU); - } - - /*** - * A convenience method to send the FTP STOU command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link FTPClient} - * , which will handle all low level details for you. - * @param pathname The base pathname to use for the file when stored at - * the remote end of the transfer. Some FTP servers - * require this. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - */ - public int stou(String pathname) throws IOException { - return sendCommand(FTPCmd.STOU, pathname); - } - - /*** - * A convenience method to send the FTP APPE command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link FTPClient} - * , which will handle all low level details for you. - * - * @param pathname The pathname to use for the file when stored at - * the remote end of the transfer. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int appe(String pathname) throws IOException { - return sendCommand(FTPCmd.APPE, pathname); - } - - /*** - * A convenience method to send the FTP ALLO command to the server, - * receive the reply, and return the reply code. - * - * @param bytes The number of bytes to allocate. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int allo(int bytes) throws IOException { - return sendCommand(FTPCmd.ALLO, Integer.toString(bytes)); - } - - /** - * A convenience method to send the FTP FEAT command to the server, receive the reply, - * and return the reply code. - * - * @return The reply code received by the server - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 2.2 - */ - public int feat() throws IOException { - return sendCommand(FTPCmd.FEAT); - } - - /*** - * A convenience method to send the FTP ALLO command to the server, - * receive the reply, and return the reply code. - * - * @param bytes The number of bytes to allocate. - * @param recordSize The size of a record. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int allo(int bytes, int recordSize) throws IOException { - return sendCommand(FTPCmd.ALLO, Integer.toString(bytes) + " R " + Integer.toString(recordSize)); - } - - /*** - * A convenience method to send the FTP REST command to the server, - * receive the reply, and return the reply code. - * - * @param marker The marker at which to restart a transfer. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int rest(String marker) throws IOException { - return sendCommand(FTPCmd.REST, marker); - } - - /** - * @param file name of file - * @return the status - * @throws IOException on error - * @since 2.0 - **/ - public int mdtm(String file) throws IOException { - return sendCommand(FTPCmd.MDTM, file); - } - - /** - * A convenience method to send the FTP MFMT command to the server, - * receive the reply, and return the reply code. - * - * @param pathname The pathname for which mtime is to be changed - * @param timeval Timestamp in YYYYMMDDhhmmss format - * @return The reply code received from the server. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @see http://tools.ietf.org/html/draft-somers-ftp-mfxx-04 - * @since 2.2 - **/ - public int mfmt(String pathname, String timeval) throws IOException { - return sendCommand(FTPCmd.MFMT, timeval + " " + pathname); - } - - /*** - * A convenience method to send the FTP RNFR command to the server, - * receive the reply, and return the reply code. - * - * @param pathname The pathname to rename from. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int rnfr(String pathname) throws IOException { - return sendCommand(FTPCmd.RNFR, pathname); - } - - /*** - * A convenience method to send the FTP RNTO command to the server, - * receive the reply, and return the reply code. - * - * @param pathname The pathname to rename to - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int rnto(String pathname) throws IOException { - return sendCommand(FTPCmd.RNTO, pathname); - } - - /*** - * A convenience method to send the FTP DELE command to the server, - * receive the reply, and return the reply code. - * - * @param pathname The pathname to delete. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int dele(String pathname) throws IOException { - return sendCommand(FTPCmd.DELE, pathname); - } - - /*** - * A convenience method to send the FTP RMD command to the server, - * receive the reply, and return the reply code. - * - * @param pathname The pathname of the directory to remove. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int rmd(String pathname) throws IOException { - return sendCommand(FTPCmd.RMD, pathname); - } - - /*** - * A convenience method to send the FTP MKD command to the server, - * receive the reply, and return the reply code. - * - * @param pathname The pathname of the new directory to create. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int mkd(String pathname) throws IOException { - return sendCommand(FTPCmd.MKD, pathname); - } - - /*** - * A convenience method to send the FTP PWD command to the server, - * receive the reply, and return the reply code. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int pwd() throws IOException { - return sendCommand(FTPCmd.PWD); - } - - /*** - * A convenience method to send the FTP LIST command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link FTPClient} - * , which will handle all low level details for you. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int list() throws IOException { - return sendCommand(FTPCmd.LIST); - } - - /*** - * A convenience method to send the FTP LIST command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link FTPClient} - * , which will handle all low level details for you. - * - * @param pathname The pathname to list, - * may be {@code null} in which case the command is sent with no parameters - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int list(String pathname) throws IOException { - return sendCommand(FTPCmd.LIST, pathname); - } - - /** - * A convenience method to send the FTP MLSD command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link FTPClient} - * , which will handle all low level details for you. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 3.0 - */ - public int mlsd() throws IOException { - return sendCommand(FTPCmd.MLSD); - } - - /** - * A convenience method to send the FTP MLSD command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link FTPClient} - * , which will handle all low level details for you. - * - * @param path the path to report on - * @return The reply code received from the server, - * may be {@code null} in which case the command is sent with no parameters - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 3.0 - */ - public int mlsd(String path) throws IOException { - return sendCommand(FTPCmd.MLSD, path); - } - - /** - * A convenience method to send the FTP MLST command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link FTPClient} - * , which will handle all low level details for you. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 3.0 - */ - public int mlst() throws IOException { - return sendCommand(FTPCmd.MLST); - } - - /** - * A convenience method to send the FTP MLST command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link FTPClient} - * , which will handle all low level details for you. - * - * @param path the path to report on - * @return The reply code received from the server, - * may be {@code null} in which case the command is sent with no parameters - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - * @since 3.0 - */ - public int mlst(String path) throws IOException { - return sendCommand(FTPCmd.MLST, path); - } - - /*** - * A convenience method to send the FTP NLST command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link FTPClient} - * , which will handle all low level details for you. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int nlst() throws IOException { - return sendCommand(FTPCmd.NLST); - } - - /*** - * A convenience method to send the FTP NLST command to the server, - * receive the reply, and return the reply code. Remember, it is up - * to you to manage the data connection. If you don't need this low - * level of access, use {@link FTPClient} - * , which will handle all low level details for you. - * - * @param pathname The pathname to list, - * may be {@code null} in which case the command is sent with no parameters - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int nlst(String pathname) throws IOException { - return sendCommand(FTPCmd.NLST, pathname); - } - - /*** - * A convenience method to send the FTP SITE command to the server, - * receive the reply, and return the reply code. - * - * @param parameters The site parameters to send. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int site(String parameters) throws IOException { - return sendCommand(FTPCmd.SITE, parameters); - } - - /*** - * A convenience method to send the FTP SYST command to the server, - * receive the reply, and return the reply code. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int syst() throws IOException { - return sendCommand(FTPCmd.SYST); - } - - /*** - * A convenience method to send the FTP STAT command to the server, - * receive the reply, and return the reply code. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int stat() throws IOException { - return sendCommand(FTPCmd.STAT); - } - - /*** - * A convenience method to send the FTP STAT command to the server, - * receive the reply, and return the reply code. - * - * @param pathname A pathname to list. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int stat(String pathname) throws IOException { - return sendCommand(FTPCmd.STAT, pathname); - } - - /*** - * A convenience method to send the FTP HELP command to the server, - * receive the reply, and return the reply code. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int help() throws IOException { - return sendCommand(FTPCmd.HELP); - } - - /*** - * A convenience method to send the FTP HELP command to the server, - * receive the reply, and return the reply code. - * - * @param command The command name on which to request help. - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int help(String command) throws IOException { - return sendCommand(FTPCmd.HELP, command); - } - - /*** - * A convenience method to send the FTP NOOP command to the server, - * receive the reply, and return the reply code. - * - * @return The reply code received from the server. - * @throws FTPConnectionClosedException - * If the FTP server prematurely closes the connection as a result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending the - * command or receiving the server reply. - ***/ - public int noop() throws IOException { - return sendCommand(FTPCmd.NOOP); - } - - /** - * Return whether strict multiline parsing is enabled, as per RFC 959, section 4.2. - * - * @return True if strict, false if lenient - * @since 2.0 - */ - public boolean isStrictMultilineParsing() { - return strictMultilineParsing; - } - - /** - * Set strict multiline parsing. - * - * @param strictMultilineParsing the setting - * @since 2.0 - */ - public void setStrictMultilineParsing(boolean strictMultilineParsing) { - this.strictMultilineParsing = strictMultilineParsing; - } - - /** - * Return whether strict non-multiline parsing is enabled, as per RFC 959, section 4.2. - *

- * The default is true, which requires the 3 digit code be followed by space and some text. - *
- * If false, only the 3 digit code is required (as was the case for versions up to 3.5) - *
- * - * @return True if strict (default), false if additional checks are not made - * @since 3.6 - */ - public boolean isStrictReplyParsing() { - return strictReplyParsing; - } - - /** - * Set strict non-multiline parsing. - *

- * If true, it requires the 3 digit code be followed by space and some text. - *
- * If false, only the 3 digit code is required (as was the case for versions up to 3.5) - *

- * This should not be required by a well-behaved FTP server - *
- * - * @param strictReplyParsing the setting - * @since 3.6 - */ - public void setStrictReplyParsing(boolean strictReplyParsing) { - this.strictReplyParsing = strictReplyParsing; - } - - /** - * Provide command support to super-class - */ - @Override protected ProtocolCommandSupport getCommandSupport() { - return _commandSupport_; - } -} - -/* Emacs configuration - * Local variables: ** - * mode: java ** - * c-basic-offset: 4 ** - * indent-tabs-mode: nil ** - * End: ** - */ diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPClient.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPClient.java deleted file mode 100644 index 4bcf98dc..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPClient.java +++ /dev/null @@ -1,3787 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -import aria.apache.commons.net.SocketClient; -import aria.apache.commons.net.ftp.parser.ParserInitializationException; -import aria.apache.commons.net.io.CopyStreamAdapter; -import aria.apache.commons.net.io.CopyStreamEvent; -import aria.apache.commons.net.io.CopyStreamException; -import aria.apache.commons.net.io.CopyStreamListener; -import aria.apache.commons.net.io.FromNetASCIIInputStream; -import aria.apache.commons.net.io.SocketInputStream; -import aria.apache.commons.net.io.SocketOutputStream; -import aria.apache.commons.net.io.ToNetASCIIOutputStream; -import aria.apache.commons.net.io.Util; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Reader; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; -import java.net.SocketTimeoutException; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Locale; -import java.util.Properties; -import java.util.Random; -import java.util.Set; - -import aria.apache.commons.net.MalformedServerReplyException; -import aria.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory; -import aria.apache.commons.net.ftp.parser.FTPFileEntryParserFactory; -import aria.apache.commons.net.ftp.parser.MLSxEntryParser; -import aria.apache.commons.net.io.CRLFLineReader; - -/** - * FTPClient encapsulates all the functionality necessary to store and - * retrieve files from an FTP server. This class takes care of all - * low level details of interacting with an FTP server and provides - * a convenient higher level interface. As with all classes derived - * from {@link SocketClient}, - * you must first connect to the server with - * {@link SocketClient#connect connect } - * before doing anything, and finally - * {@link SocketClient#disconnect disconnect } - * after you're completely finished interacting with the server. - * Then you need to check the FTP reply code to see if the connection - * was successful. For example: - *

- *    FTPClient ftp = new FTPClient();
- *    FTPClientConfig config = new FTPClientConfig();
- *    config.setXXX(YYY); // change required options
- *    // for example config.setServerTimeZoneId("Pacific/Pitcairn")
- *    ftp.configure(config );
- *    boolean error = false;
- *    try {
- *      int reply;
- *      String server = "ftp.example.com";
- *      ftp.connect(server);
- *      System.out.println("Connected to " + server + ".");
- *      System.out.print(ftp.getReplyString());
- *
- *      // After connection attempt, you should check the reply code to verify
- *      // success.
- *      reply = ftp.getReplyCode();
- *
- *      if(!FTPReply.isPositiveCompletion(reply)) {
- *        ftp.disconnect();
- *        System.err.println("FTP server refused connection.");
- *        System.exit(1);
- *      }
- *      ... // transfer files
- *      ftp.logout();
- *    } catch(IOException e) {
- *      error = true;
- *      e.printStackTrace();
- *    } finally {
- *      if(ftp.isConnected()) {
- *        try {
- *          ftp.disconnect();
- *        } catch(IOException ioe) {
- *          // do nothing
- *        }
- *      }
- *      System.exit(error ? 1 : 0);
- *    }
- * 
- *

- * Immediately after connecting is the only real time you need to check the - * reply code (because connect is of type void). The convention for all the - * FTP command methods in FTPClient is such that they either return a - * boolean value or some other value. - * The boolean methods return true on a successful completion reply from - * the FTP server and false on a reply resulting in an error condition or - * failure. The methods returning a value other than boolean return a value - * containing the higher level data produced by the FTP command, or null if a - * reply resulted in an error condition or failure. If you want to access - * the exact FTP reply code causing a success or failure, you must call - * {@link FTP#getReplyCode getReplyCode } after - * a success or failure. - *

- * The default settings for FTPClient are for it to use - * FTP.ASCII_FILE_TYPE , - * FTP.NON_PRINT_TEXT_FORMAT , - * FTP.STREAM_TRANSFER_MODE , and - * FTP.FILE_STRUCTURE . The only file types directly supported - * are FTP.ASCII_FILE_TYPE and - * FTP.BINARY_FILE_TYPE . Because there are at least 4 - * different EBCDIC encodings, we have opted not to provide direct support - * for EBCDIC. To transfer EBCDIC and other unsupported file types you - * must create your own filter InputStreams and OutputStreams and wrap - * them around the streams returned or required by the FTPClient methods. - * FTPClient uses the {@link ToNetASCIIOutputStream NetASCII} - * filter streams to provide transparent handling of ASCII files. We will - * consider incorporating EBCDIC support if there is enough demand. - *

- * FTP.NON_PRINT_TEXT_FORMAT , - * FTP.STREAM_TRANSFER_MODE , and - * FTP.FILE_STRUCTURE are the only supported formats, - * transfer modes, and file structures. - *

- * Because the handling of sockets on different platforms can differ - * significantly, the FTPClient automatically issues a new PORT (or EPRT) command - * prior to every transfer requiring that the server connect to the client's - * data port. This ensures identical problem-free behavior on Windows, Unix, - * and Macintosh platforms. Additionally, it relieves programmers from - * having to issue the PORT (or EPRT) command themselves and dealing with platform - * dependent issues. - *

- * Additionally, for security purposes, all data connections to the - * client are verified to ensure that they originated from the intended - * party (host and port). If a data connection is initiated by an unexpected - * party, the command will close the socket and throw an IOException. You - * may disable this behavior with - * {@link #setRemoteVerificationEnabled setRemoteVerificationEnabled()}. - *

- * You should keep in mind that the FTP server may choose to prematurely - * close a connection if the client has been idle for longer than a - * given time period (usually 900 seconds). The FTPClient class will detect a - * premature FTP server connection closing when it receives a - * {@link FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } - * response to a command. - * When that occurs, the FTP class method encountering that reply will throw - * an {@link FTPConnectionClosedException} - * . - * FTPConnectionClosedException - * is a subclass of IOException and therefore need not be - * caught separately, but if you are going to catch it separately, its - * catch block must appear before the more general IOException - * catch block. When you encounter an - * {@link FTPConnectionClosedException} - * , you must disconnect the connection with - * {@link #disconnect disconnect() } to properly clean up the - * system resources used by FTPClient. Before disconnecting, you may check the - * last reply code and text with - * {@link FTP#getReplyCode getReplyCode }, - * {@link FTP#getReplyString getReplyString }, - * and - * {@link FTP#getReplyStrings getReplyStrings}. - * You may avoid server disconnections while the client is idle by - * periodically sending NOOP commands to the server. - *

- * Rather than list it separately for each method, we mention here that - * every method communicating with the server and throwing an IOException - * can also throw a - * {@link MalformedServerReplyException} - * , which is a subclass - * of IOException. A MalformedServerReplyException will be thrown when - * the reply received from the server deviates enough from the protocol - * specification that it cannot be interpreted in a useful manner despite - * attempts to be as lenient as possible. - *

- * Listing API Examples - * Both paged and unpaged examples of directory listings are available, - * as follows: - *

- * Unpaged (whole list) access, using a parser accessible by auto-detect: - *

- *    FTPClient f = new FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = f.listFiles(directory);
- * 
- *

- * Paged access, using a parser not accessible by auto-detect. The class - * defined in the first parameter of initateListParsing should be derived - * from org.apache.commons.net.FTPFileEntryParser: - *

- *    FTPClient f = new FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPListParseEngine engine =
- *       f.initiateListParsing("com.whatever.YourOwnParser", directory);
- *
- *    while (engine.hasNext()) {
- *       FTPFile[] files = engine.getNext(25);  // "page size" you want
- *       //do whatever you want with these files, display them, etc.
- *       //expensive FTPFile objects not created until needed.
- *    }
- * 
- *

- * Paged access, using a parser accessible by auto-detect: - *

- *    FTPClient f = new FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPListParseEngine engine = f.initiateListParsing(directory);
- *
- *    while (engine.hasNext()) {
- *       FTPFile[] files = engine.getNext(25);  // "page size" you want
- *       //do whatever you want with these files, display them, etc.
- *       //expensive FTPFile objects not created until needed.
- *    }
- * 
- *

- * For examples of using FTPClient on servers whose directory listings - *

see {@link FTPClientConfig FTPClientConfig}. - *

- * Control channel keep-alive feature: - *

- * Please note: this does not apply to the methods where the user is responsible for writing - * or reading - * the data stream, i.e. {@link #retrieveFileStream(String)} , {@link #storeFileStream(String)} - * and the other xxxFileStream methods - *

- * During file transfers, the data connection is busy, but the control connection is idle. - * FTP servers know that the control connection is in use, so won't close it through lack of - * activity, - * but it's a lot harder for network routers to know that the control and data connections are - * associated - * with each other. - * Some routers may treat the control connection as idle, and disconnect it if the transfer over the - * data - * connection takes longer than the allowable idle time for the router. - *
- * One solution to this is to send a safe command (i.e. NOOP) over the control connection to reset - * the router's - * idle timer. This is enabled as follows: - *

- *     ftpClient.setControlKeepAliveTimeout(300); // set timeout to 5 minutes
- * 
- * This will cause the file upload/download methods to send a NOOP approximately every 5 minutes. - * The following public methods support this: - * - * This feature does not apply to the methods where the user is responsible for writing or reading - * the data stream, i.e. {@link #retrieveFileStream(String)} , {@link #storeFileStream(String)} - * and the other xxxFileStream methods. - * In such cases, the user is responsible for keeping the control connection alive if necessary. - *

- * The implementation currently uses a {@link CopyStreamListener} which is passed to the - * {@link Util#copyStream(InputStream, OutputStream, int, long, CopyStreamListener, boolean)} - * method, so the timing is partially dependent on how long each block transfer takes. - * - * @see #FTP_SYSTEM_TYPE - * @see #SYSTEM_TYPE_PROPERTIES - * @see FTP - * @see FTPConnectionClosedException - * @see FTPFileEntryParser - * @see FTPFileEntryParserFactory - * @see DefaultFTPFileEntryParserFactory - * @see FTPClientConfig - * @see MalformedServerReplyException - */ -public class FTPClient extends FTP implements Configurable { - /** - * The system property ({@value}) which can be used to override the system type.
- * If defined, the value will be used to create any automatically created parsers. - * - * @since 3.0 - */ - public static final String FTP_SYSTEM_TYPE = "org.apache.commons.net.ftp.systemType"; - - /** - * The system property ({@value}) which can be used as the default system type.
- * If defined, the value will be used if the SYST command fails. - * - * @since 3.1 - */ - public static final String FTP_SYSTEM_TYPE_DEFAULT = - "org.apache.commons.net.ftp.systemType.default"; - - /** - * The name of an optional systemType properties file ({@value}), which is loaded - * using {@link Class#getResourceAsStream(String)}.
- * The entries are the systemType (as determined by {@link FTPClient#getSystemType}) - * and the values are the replacement type or parserClass, which is passed to - * {@link FTPFileEntryParserFactory#createFileEntryParser(String)}.
- * For example: - *

-   * Plan 9=Unix
-   * OS410=OS400FTPEntryParser
-   * 
- * - * @since 3.0 - */ - public static final String SYSTEM_TYPE_PROPERTIES = "/systemType.properties"; - - /** - * A constant indicating the FTP session is expecting all transfers - * to occur between the client (local) and server and that the server - * should connect to the client's data port to initiate a data transfer. - * This is the default data connection mode when and FTPClient instance - * is created. - */ - public static final int ACTIVE_LOCAL_DATA_CONNECTION_MODE = 0; - /** - * A constant indicating the FTP session is expecting all transfers - * to occur between two remote servers and that the server - * the client is connected to should connect to the other server's - * data port to initiate a data transfer. - */ - public static final int ACTIVE_REMOTE_DATA_CONNECTION_MODE = 1; - /** - * A constant indicating the FTP session is expecting all transfers - * to occur between the client (local) and server and that the server - * is in passive mode, requiring the client to connect to the - * server's data port to initiate a transfer. - */ - public static final int PASSIVE_LOCAL_DATA_CONNECTION_MODE = 2; - /** - * A constant indicating the FTP session is expecting all transfers - * to occur between two remote servers and that the server - * the client is connected to is in passive mode, requiring the other - * server to connect to the first server's data port to initiate a data - * transfer. - */ - public static final int PASSIVE_REMOTE_DATA_CONNECTION_MODE = 3; - - private int __dataConnectionMode; - private int __dataTimeout; - private int __passivePort; - private String __passiveHost; - private final Random __random; - private int __activeMinPort; - private int __activeMaxPort; - private InetAddress __activeExternalHost; - private InetAddress __reportActiveExternalHost; - // overrides __activeExternalHost in EPRT/PORT commands - /** The address to bind to on passive connections, if necessary. */ - private InetAddress __passiveLocalHost; - - private int __fileType; - @SuppressWarnings("unused") // fields are written, but currently not read - private int __fileFormat; - @SuppressWarnings("unused") // field is written, but currently not read - private int __fileStructure; - @SuppressWarnings("unused") // field is written, but currently not read - private int __fileTransferMode; - private boolean __remoteVerificationEnabled; - private long __restartOffset; - private FTPFileEntryParserFactory __parserFactory; - private int __bufferSize; // buffersize for buffered data streams - private int __sendDataSocketBufferSize; - private int __receiveDataSocketBufferSize; - private boolean __listHiddenFiles; - private boolean __useEPSVwithIPv4; // whether to attempt EPSV with an IPv4 connection - - // __systemName is a cached value that should not be referenced directly - // except when assigned in getSystemName and __initDefaults. - private String __systemName; - - // __entryParser is a cached value that should not be referenced directly - // except when assigned in listFiles(String, String) and __initDefaults. - private FTPFileEntryParser __entryParser; - - // Key used to create the parser; necessary to ensure that the parser type is not ignored - private String __entryParserKey; - - private FTPClientConfig __configuration; - - // Listener used by store/retrieve methods to handle keepalive - private CopyStreamListener __copyStreamListener; - - // How long to wait before sending another control keep-alive message - private long __controlKeepAliveTimeout; - - // How long to wait (ms) for keepalive message replies before continuing - // Most FTP servers don't seem to support concurrent control and data connection usage - private int __controlKeepAliveReplyTimeout = 1000; - - /** - * Enable or disable replacement of internal IP in passive mode. Default enabled - * using {code NatServerResolverImpl}. - */ - private HostnameResolver __passiveNatWorkaroundStrategy = new NatServerResolverImpl(this); - - /** Pattern for PASV mode responses. Groups: (n,n,n,n),(n),(n) */ - private static final java.util.regex.Pattern __PARMS_PAT; - - static { - __PARMS_PAT = java.util.regex.Pattern.compile( - "(\\d{1,3},\\d{1,3},\\d{1,3},\\d{1,3}),(\\d{1,3}),(\\d{1,3})"); - } - - /** Controls the automatic server encoding detection (only UTF-8 supported). */ - private boolean __autodetectEncoding = false; - - /** Map of FEAT responses. If null, has not been initialised. */ - private HashMap> __featuresMap; - - private static class PropertiesSingleton { - - static final Properties PROPERTIES; - - static { - InputStream resourceAsStream = FTPClient.class.getResourceAsStream(SYSTEM_TYPE_PROPERTIES); - Properties p = null; - if (resourceAsStream != null) { - p = new Properties(); - try { - p.load(resourceAsStream); - } catch (IOException e) { - // Ignored - } finally { - try { - resourceAsStream.close(); - } catch (IOException e) { - // Ignored - } - } - } - PROPERTIES = p; - } - } - - private static Properties getOverrideProperties() { - return PropertiesSingleton.PROPERTIES; - } - - /** - * Default FTPClient constructor. Creates a new FTPClient instance - * with the data connection mode set to - * ACTIVE_LOCAL_DATA_CONNECTION_MODE , the file type - * set to FTP.ASCII_FILE_TYPE , the - * file format set to FTP.NON_PRINT_TEXT_FORMAT , - * the file structure set to FTP.FILE_STRUCTURE , and - * the transfer mode set to FTP.STREAM_TRANSFER_MODE . - *

- * The list parsing auto-detect feature can be configured to use lenient future - * dates (short dates may be up to one day in the future) as follows: - *

-   * FTPClient ftp = new FTPClient();
-   * FTPClientConfig config = new FTPClientConfig();
-   * config.setLenientFutureDates(true);
-   * ftp.configure(config );
-   * 
- */ - public FTPClient() { - __initDefaults(); - __dataTimeout = -1; - __remoteVerificationEnabled = true; - __parserFactory = new DefaultFTPFileEntryParserFactory(); - __configuration = null; - __listHiddenFiles = false; - __useEPSVwithIPv4 = false; - __random = new Random(); - __passiveLocalHost = null; - } - - private void __initDefaults() { - __dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE; - __passiveHost = null; - __passivePort = -1; - __activeExternalHost = null; - __reportActiveExternalHost = null; - __activeMinPort = 0; - __activeMaxPort = 0; - __fileType = FTP.ASCII_FILE_TYPE; - __fileStructure = FTP.FILE_STRUCTURE; - __fileFormat = FTP.NON_PRINT_TEXT_FORMAT; - __fileTransferMode = FTP.STREAM_TRANSFER_MODE; - __restartOffset = 0; - __systemName = null; - __entryParser = null; - __entryParserKey = ""; - __featuresMap = null; - } - - /** - * Parse the pathname from a CWD reply. - *

- * According to RFC959 (http://www.ietf.org/rfc/rfc959.txt), - * it should be the same as for MKD i.e. - * {@code 257""[commentary]} - * where any double-quotes in {@code } are doubled. - * Unlike MKD, the commentary is optional. - *

- * However, see NET-442 for an exception. - * - * @return the pathname, without enclosing quotes, - * or the full string after the reply code and space if the syntax is invalid - * (i.e. enclosing quotes are missing or embedded quotes are not doubled) - */ - // package protected for access by test cases - static String __parsePathname(String reply) { - String param = reply.substring(REPLY_CODE_LEN + 1); - if (param.startsWith("\"")) { - StringBuilder sb = new StringBuilder(); - boolean quoteSeen = false; - // start after initial quote - for (int i = 1; i < param.length(); i++) { - char ch = param.charAt(i); - if (ch == '"') { - if (quoteSeen) { - sb.append(ch); - quoteSeen = false; - } else { - // don't output yet, in case doubled - quoteSeen = true; - } - } else { - if (quoteSeen) { // found lone trailing quote within string - return sb.toString(); - } - sb.append(ch); // just another character - } - } - if (quoteSeen) { // found lone trailing quote at end of string - return sb.toString(); - } - } - // malformed reply, return all after reply code and space - return param; - } - - /** - * @param reply the reply to parse - * @throws MalformedServerReplyException if the server reply does not match (n,n,n,n),(n),(n) - * @since 3.1 - */ - protected void _parsePassiveModeReply(String reply) throws MalformedServerReplyException { - java.util.regex.Matcher m = __PARMS_PAT.matcher(reply); - if (!m.find()) { - throw new MalformedServerReplyException( - "Could not parse passive host information.\nServer Reply: " + reply); - } - - __passiveHost = m.group(1).replace(',', '.'); // Fix up to look like IP address - - try { - int oct1 = Integer.parseInt(m.group(2)); - int oct2 = Integer.parseInt(m.group(3)); - __passivePort = (oct1 << 8) | oct2; - } catch (NumberFormatException e) { - throw new MalformedServerReplyException( - "Could not parse passive port information.\nServer Reply: " + reply); - } - - if (__passiveNatWorkaroundStrategy != null) { - try { - String passiveHost = __passiveNatWorkaroundStrategy.resolve(__passiveHost); - if (!__passiveHost.equals(passiveHost)) { - fireReplyReceived(0, "[Replacing PASV mode reply address " - + __passiveHost - + " with " - + passiveHost - + "]\n"); - __passiveHost = passiveHost; - } - } catch (UnknownHostException e) { // Should not happen as we are passing in an IP address - throw new MalformedServerReplyException( - "Could not parse passive host information.\nServer Reply: " + reply); - } - } - } - - protected void _parseExtendedPassiveModeReply(String reply) throws MalformedServerReplyException { - reply = reply.substring(reply.indexOf('(') + 1, reply.indexOf(')')).trim(); - - char delim1, delim2, delim3, delim4; - delim1 = reply.charAt(0); - delim2 = reply.charAt(1); - delim3 = reply.charAt(2); - delim4 = reply.charAt(reply.length() - 1); - - if (!(delim1 == delim2) || !(delim2 == delim3) || !(delim3 == delim4)) { - throw new MalformedServerReplyException( - "Could not parse extended passive host information.\nServer Reply: " + reply); - } - - int port; - try { - port = Integer.parseInt(reply.substring(3, reply.length() - 1)); - } catch (NumberFormatException e) { - throw new MalformedServerReplyException( - "Could not parse extended passive host information.\nServer Reply: " + reply); - } - - // in EPSV mode, the passive host address is implicit - __passiveHost = getRemoteAddress().getHostAddress(); - __passivePort = port; - } - - private boolean __storeFile(FTPCmd command, String remote, InputStream local) throws IOException { - return _storeFile(command.getCommand(), remote, local); - } - - /** - * @param command the command to send - * @param remote the remote file name - * @param local the local file name - * @return true if successful - * @throws IOException on error - * @since 3.1 - */ - protected boolean _storeFile(String command, String remote, InputStream local) - throws IOException { - Socket socket = _openDataConnection_(command, remote); - - if (socket == null) { - return false; - } - - final OutputStream output; - - if (__fileType == ASCII_FILE_TYPE) { - output = new ToNetASCIIOutputStream(getBufferedOutputStream(socket.getOutputStream())); - } else { - output = getBufferedOutputStream(socket.getOutputStream()); - } - - CSL csl = null; - if (__controlKeepAliveTimeout > 0) { - if (mListener != null) { - csl = new CSL(this, __controlKeepAliveTimeout, __controlKeepAliveReplyTimeout, mListener); - } else { - csl = new CSL(this, __controlKeepAliveTimeout, __controlKeepAliveReplyTimeout); - } - } - - // Treat everything else as binary for now - try { - Util.copyStream(local, output, getBufferSize(), CopyStreamEvent.UNKNOWN_STREAM_SIZE, - __mergeListeners(csl), false); - } catch (IOException e) { - Util.closeQuietly(socket); // ignore close errors here - if (csl != null) { - csl.cleanUp(); // fetch any outstanding keepalive replies - } - throw e; - } - - output.close(); // ensure the file is fully written - socket.close(); // done writing the file - if (csl != null) { - csl.cleanUp(); // fetch any outstanding keepalive replies - } - // Get the transfer response - boolean ok = completePendingCommand(); - return ok; - } - - private OutputStream __storeFileStream(FTPCmd command, String remote) throws IOException { - return _storeFileStream(command.getCommand(), remote); - } - - /** - * @param command the command to send - * @param remote the remote file name - * @return the output stream to write to - * @throws IOException on error - * @since 3.1 - */ - protected OutputStream _storeFileStream(String command, String remote) throws IOException { - Socket socket = _openDataConnection_(command, remote); - - if (socket == null) { - return null; - } - - final OutputStream output; - if (__fileType == ASCII_FILE_TYPE) { - // We buffer ascii transfers because the buffering has to - // be interposed between ToNetASCIIOutputSream and the underlying - // socket output stream. We don't buffer binary transfers - // because we don't want to impose a buffering policy on the - // programmer if possible. Programmers can decide on their - // own if they want to wrap the SocketOutputStream we return - // for file types other than ASCII. - output = new ToNetASCIIOutputStream(getBufferedOutputStream(socket.getOutputStream())); - } else { - output = socket.getOutputStream(); - } - return new SocketOutputStream(socket, output); - } - - /** - * Establishes a data connection with the FTP server, returning - * a Socket for the connection if successful. If a restart - * offset has been set with {@link #setRestartOffset(long)}, - * a REST command is issued to the server with the offset as - * an argument before establishing the data connection. Active - * mode connections also cause a local PORT command to be issued. - * - * @param command The int representation of the FTP command to send. - * @param arg The arguments to the FTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return A Socket corresponding to the established data connection. - * Null is returned if an FTP protocol error is reported at - * any point during the establishment and initialization of - * the connection. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @deprecated (3.3) Use {@link #_openDataConnection_(FTPCmd, String)} instead - */ - @Deprecated protected Socket _openDataConnection_(int command, String arg) throws IOException { - return _openDataConnection_(FTPCommand.getCommand(command), arg); - } - - /** - * Establishes a data connection with the FTP server, returning - * a Socket for the connection if successful. If a restart - * offset has been set with {@link #setRestartOffset(long)}, - * a REST command is issued to the server with the offset as - * an argument before establishing the data connection. Active - * mode connections also cause a local PORT command to be issued. - * - * @param command The int representation of the FTP command to send. - * @param arg The arguments to the FTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return A Socket corresponding to the established data connection. - * Null is returned if an FTP protocol error is reported at - * any point during the establishment and initialization of - * the connection. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @since 3.3 - */ - protected Socket _openDataConnection_(FTPCmd command, String arg) throws IOException { - return _openDataConnection_(command.getCommand(), arg); - } - - /** - * Establishes a data connection with the FTP server, returning - * a Socket for the connection if successful. If a restart - * offset has been set with {@link #setRestartOffset(long)}, - * a REST command is issued to the server with the offset as - * an argument before establishing the data connection. Active - * mode connections also cause a local PORT command to be issued. - * - * @param command The text representation of the FTP command to send. - * @param arg The arguments to the FTP command. If this parameter is - * set to null, then the command is sent with no argument. - * @return A Socket corresponding to the established data connection. - * Null is returned if an FTP protocol error is reported at - * any point during the establishment and initialization of - * the connection. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @since 3.1 - */ - protected Socket _openDataConnection_(String command, String arg) throws IOException { - if (__dataConnectionMode != ACTIVE_LOCAL_DATA_CONNECTION_MODE - && __dataConnectionMode != PASSIVE_LOCAL_DATA_CONNECTION_MODE) { - return null; - } - - final boolean isInet6Address = getRemoteAddress() instanceof Inet6Address; - - Socket socket; - - if (__dataConnectionMode == ACTIVE_LOCAL_DATA_CONNECTION_MODE) { - // if no activePortRange was set (correctly) -> getActivePort() = 0 - // -> new ServerSocket(0) -> bind to any free local port - ServerSocket server = - _serverSocketFactory_.createServerSocket(getActivePort(), 1, getHostAddress()); - - try { - // Try EPRT only if remote server is over IPv6, if not use PORT, - // because EPRT has no advantage over PORT on IPv4. - // It could even have the disadvantage, - // that EPRT will make the data connection fail, because - // today's intelligent NAT Firewalls are able to - // substitute IP addresses in the PORT command, - // but might not be able to recognize the EPRT command. - if (isInet6Address) { - if (!FTPReply.isPositiveCompletion(eprt(getReportHostAddress(), server.getLocalPort()))) { - return null; - } - } else { - if (!FTPReply.isPositiveCompletion(port(getReportHostAddress(), server.getLocalPort()))) { - return null; - } - } - - if ((__restartOffset > 0) && !restart(__restartOffset)) { - return null; - } - - if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) { - return null; - } - - // For now, let's just use the data timeout value for waiting for - // the data connection. It may be desirable to let this be a - // separately configurable value. In any case, we really want - // to allow preventing the accept from blocking indefinitely. - if (__dataTimeout >= 0) { - server.setSoTimeout(__dataTimeout); - } - socket = server.accept(); - - // Ensure the timeout is set before any commands are issued on the new socket - if (__dataTimeout >= 0) { - socket.setSoTimeout(__dataTimeout); - } - if (__receiveDataSocketBufferSize > 0) { - socket.setReceiveBufferSize(__receiveDataSocketBufferSize); - } - if (__sendDataSocketBufferSize > 0) { - socket.setSendBufferSize(__sendDataSocketBufferSize); - } - } finally { - server.close(); - } - } else { // We must be in PASSIVE_LOCAL_DATA_CONNECTION_MODE - - // Try EPSV command first on IPv6 - and IPv4 if enabled. - // When using IPv4 with NAT it has the advantage - // to work with more rare configurations. - // E.g. if FTP server has a static PASV address (external network) - // and the client is coming from another internal network. - // In that case the data connection after PASV command would fail, - // while EPSV would make the client succeed by taking just the port. - boolean attemptEPSV = isUseEPSVwithIPv4() || isInet6Address; - if (attemptEPSV && epsv() == FTPReply.ENTERING_EPSV_MODE) { - _parseExtendedPassiveModeReply(_replyLines.get(0)); - } else { - if (isInet6Address) { - return null; // Must use EPSV for IPV6 - } - // If EPSV failed on IPV4, revert to PASV - if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) { - return null; - } - _parsePassiveModeReply(_replyLines.get(0)); - } - - socket = _socketFactory_.createSocket(); - if (__receiveDataSocketBufferSize > 0) { - socket.setReceiveBufferSize(__receiveDataSocketBufferSize); - } - if (__sendDataSocketBufferSize > 0) { - socket.setSendBufferSize(__sendDataSocketBufferSize); - } - if (__passiveLocalHost != null) { - socket.bind(new InetSocketAddress(__passiveLocalHost, 0)); - } - - // For now, let's just use the data timeout value for waiting for - // the data connection. It may be desirable to let this be a - // separately configurable value. In any case, we really want - // to allow preventing the accept from blocking indefinitely. - if (__dataTimeout >= 0) { - socket.setSoTimeout(__dataTimeout); - } - - socket.connect(new InetSocketAddress(__passiveHost, __passivePort), connectTimeout); - if ((__restartOffset > 0) && !restart(__restartOffset)) { - socket.close(); - return null; - } - - if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) { - socket.close(); - return null; - } - } - - if (__remoteVerificationEnabled && !verifyRemote(socket)) { - socket.close(); - - throw new IOException("Host attempting data connection " - + socket.getInetAddress().getHostAddress() - + " is not same as server " - + getRemoteAddress().getHostAddress()); - } - - return socket; - } - - @Override protected void _connectAction_() throws IOException { - _connectAction_(null); - } - - /** - * @param socketIsReader the reader to reuse (if non-null) - * @throws IOException on error - * @since 3.4 - */ - @Override protected void _connectAction_(Reader socketIsReader) throws IOException { - super._connectAction_(socketIsReader); // sets up _input_ and _output_ - __initDefaults(); - // must be after super._connectAction_(), because otherwise we get an - // Exception claiming we're not connected - if (__autodetectEncoding) { - ArrayList oldReplyLines = new ArrayList(_replyLines); - int oldReplyCode = _replyCode; - if (hasFeature("UTF8") || hasFeature("UTF-8")) // UTF8 appears to be the default - { - setControlEncoding("UTF-8"); - _controlInput_ = new CRLFLineReader(new InputStreamReader(_input_, getControlEncoding())); - _controlOutput_ = - new BufferedWriter(new OutputStreamWriter(_output_, getControlEncoding())); - } - // restore the original reply (server greeting) - _replyLines.clear(); - _replyLines.addAll(oldReplyLines); - _replyCode = oldReplyCode; - _newReplyString = true; - } - } - - /** - * Sets the timeout in milliseconds to use when reading from the - * data connection. This timeout will be set immediately after - * opening the data connection, provided that the value is ≥ 0. - *

- * Note: the timeout will also be applied when calling accept() - * whilst establishing an active local data connection. - * - * @param timeout The default timeout in milliseconds that is used when - * opening a data connection socket. The value 0 means an infinite timeout. - */ - public void setDataTimeout(int timeout) { - __dataTimeout = timeout; - } - - /** - * set the factory used for parser creation to the supplied factory object. - * - * @param parserFactory factory object used to create FTPFileEntryParsers - * @see FTPFileEntryParserFactory - * @see DefaultFTPFileEntryParserFactory - */ - public void setParserFactory(FTPFileEntryParserFactory parserFactory) { - __parserFactory = parserFactory; - } - - /** - * Closes the connection to the FTP server and restores - * connection parameters to the default values. - * - * @throws IOException If an error occurs while disconnecting. - */ - @Override public void disconnect() throws IOException { - super.disconnect(); - __initDefaults(); - } - - /** - * Enable or disable verification that the remote host taking part - * of a data connection is the same as the host to which the control - * connection is attached. The default is for verification to be - * enabled. You may set this value at any time, whether the - * FTPClient is currently connected or not. - * - * @param enable True to enable verification, false to disable verification. - */ - public void setRemoteVerificationEnabled(boolean enable) { - __remoteVerificationEnabled = enable; - } - - /** - * Return whether or not verification of the remote host participating - * in data connections is enabled. The default behavior is for - * verification to be enabled. - * - * @return True if verification is enabled, false if not. - */ - public boolean isRemoteVerificationEnabled() { - return __remoteVerificationEnabled; - } - - /** - * Login to the FTP server using the provided username and password. - * - * @param username The username to login under. - * @param password The password to use. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean login(String username, String password) throws IOException { - - user(username); - - if (FTPReply.isPositiveCompletion(_replyCode)) { - return true; - } - - // If we get here, we either have an error code, or an intermmediate - // reply requesting password. - if (!FTPReply.isPositiveIntermediate(_replyCode)) { - return false; - } - - return FTPReply.isPositiveCompletion(pass(password)); - } - - /** - * Login to the FTP server using the provided username, password, - * and account. If no account is required by the server, only - * the username and password, the account information is not used. - * - * @param username The username to login under. - * @param password The password to use. - * @param account The account to use. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean login(String username, String password, String account) throws IOException { - user(username); - - if (FTPReply.isPositiveCompletion(_replyCode)) { - return true; - } - - // If we get here, we either have an error code, or an intermmediate - // reply requesting password. - if (!FTPReply.isPositiveIntermediate(_replyCode)) { - return false; - } - - pass(password); - - if (FTPReply.isPositiveCompletion(_replyCode)) { - return true; - } - - if (!FTPReply.isPositiveIntermediate(_replyCode)) { - return false; - } - - return FTPReply.isPositiveCompletion(acct(account)); - } - - /** - * Logout of the FTP server by sending the QUIT command. - * - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean logout() throws IOException { - return FTPReply.isPositiveCompletion(quit()); - } - - /** - * Change the current working directory of the FTP session. - * - * @param pathname The new current working directory. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean changeWorkingDirectory(String pathname) throws IOException { - return FTPReply.isPositiveCompletion(cwd(pathname)); - } - - /** - * Change to the parent directory of the current working directory. - * - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean changeToParentDirectory() throws IOException { - return FTPReply.isPositiveCompletion(cdup()); - } - - /** - * Issue the FTP SMNT command. - * - * @param pathname The pathname to mount. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean structureMount(String pathname) throws IOException { - return FTPReply.isPositiveCompletion(smnt(pathname)); - } - - /** - * Reinitialize the FTP session. Not all FTP servers support this - * command, which issues the FTP REIN command. - * - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @since 3.4 (made public) - */ - public boolean reinitialize() throws IOException { - rein(); - - if (FTPReply.isPositiveCompletion(_replyCode) || (FTPReply.isPositivePreliminary(_replyCode) - && FTPReply.isPositiveCompletion(getReply()))) { - - __initDefaults(); - - return true; - } - - return false; - } - - /** - * Set the current data connection mode to - * ACTIVE_LOCAL_DATA_CONNECTION_MODE. No communication - * with the FTP server is conducted, but this causes all future data - * transfers to require the FTP server to connect to the client's - * data port. Additionally, to accommodate differences between socket - * implementations on different platforms, this method causes the - * client to issue a PORT command before every data transfer. - */ - public void enterLocalActiveMode() { - __dataConnectionMode = ACTIVE_LOCAL_DATA_CONNECTION_MODE; - __passiveHost = null; - __passivePort = -1; - } - - /** - * Set the current data connection mode to - * PASSIVE_LOCAL_DATA_CONNECTION_MODE . Use this - * method only for data transfers between the client and server. - * This method causes a PASV (or EPSV) command to be issued to the server - * before the opening of every data connection, telling the server to - * open a data port to which the client will connect to conduct - * data transfers. The FTPClient will stay in - * PASSIVE_LOCAL_DATA_CONNECTION_MODE until the - * mode is changed by calling some other method such as - * {@link #enterLocalActiveMode enterLocalActiveMode() } - *

- * N.B. currently calling any connect method will reset the mode to - * ACTIVE_LOCAL_DATA_CONNECTION_MODE. - */ - public void enterLocalPassiveMode() { - __dataConnectionMode = PASSIVE_LOCAL_DATA_CONNECTION_MODE; - // These will be set when just before a data connection is opened - // in _openDataConnection_() - __passiveHost = null; - __passivePort = -1; - } - - /** - * Set the current data connection mode to - * ACTIVE_REMOTE_DATA_CONNECTION . Use this method only - * for server to server data transfers. This method issues a PORT - * command to the server, indicating the other server and port to which - * it should connect for data transfers. You must call this method - * before EVERY server to server transfer attempt. The FTPClient will - * NOT automatically continue to issue PORT commands. You also - * must remember to call - * {@link #enterLocalActiveMode enterLocalActiveMode() } if you - * wish to return to the normal data connection mode. - * - * @param host The passive mode server accepting connections for data - * transfers. - * @param port The passive mode server's data port. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean enterRemoteActiveMode(InetAddress host, int port) throws IOException { - if (FTPReply.isPositiveCompletion(port(host, port))) { - __dataConnectionMode = ACTIVE_REMOTE_DATA_CONNECTION_MODE; - __passiveHost = null; - __passivePort = -1; - return true; - } - return false; - } - - /** - * Set the current data connection mode to - * PASSIVE_REMOTE_DATA_CONNECTION_MODE . Use this - * method only for server to server data transfers. - * This method issues a PASV command to the server, telling it to - * open a data port to which the active server will connect to conduct - * data transfers. You must call this method - * before EVERY server to server transfer attempt. The FTPClient will - * NOT automatically continue to issue PASV commands. You also - * must remember to call - * {@link #enterLocalActiveMode enterLocalActiveMode() } if you - * wish to return to the normal data connection mode. - * - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean enterRemotePassiveMode() throws IOException { - if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) { - return false; - } - - __dataConnectionMode = PASSIVE_REMOTE_DATA_CONNECTION_MODE; - _parsePassiveModeReply(_replyLines.get(0)); - - return true; - } - - /** - * Returns the hostname or IP address (in the form of a string) returned - * by the server when entering passive mode. If not in passive mode, - * returns null. This method only returns a valid value AFTER a - * data connection has been opened after a call to - * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. - * This is because FTPClient sends a PASV command to the server only - * just before opening a data connection, and not when you call - * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. - * - * @return The passive host name if in passive mode, otherwise null. - */ - public String getPassiveHost() { - return __passiveHost; - } - - /** - * If in passive mode, returns the data port of the passive host. - * This method only returns a valid value AFTER a - * data connection has been opened after a call to - * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. - * This is because FTPClient sends a PASV command to the server only - * just before opening a data connection, and not when you call - * {@link #enterLocalPassiveMode enterLocalPassiveMode()}. - * - * @return The data port of the passive server. If not in passive - * mode, undefined. - */ - public int getPassivePort() { - return __passivePort; - } - - /** - * Returns the current data connection mode (one of the - * _DATA_CONNECTION_MODE constants. - * - * @return The current data connection mode (one of the - * _DATA_CONNECTION_MODE constants. - */ - public int getDataConnectionMode() { - return __dataConnectionMode; - } - - /** - * Get the client port for active mode. - * - * @return The client port for active mode. - */ - private int getActivePort() { - if (__activeMinPort > 0 && __activeMaxPort >= __activeMinPort) { - if (__activeMaxPort == __activeMinPort) { - return __activeMaxPort; - } - // Get a random port between the min and max port range - return __random.nextInt(__activeMaxPort - __activeMinPort + 1) + __activeMinPort; - } else { - // default port - return 0; - } - } - - /** - * Get the host address for active mode; allows the local address to be overridden. - * - * @return __activeExternalHost if non-null, else getLocalAddress() - * @see #setActiveExternalIPAddress(String) - */ - private InetAddress getHostAddress() { - if (__activeExternalHost != null) { - return __activeExternalHost; - } else { - // default local address - return getLocalAddress(); - } - } - - /** - * Get the reported host address for active mode EPRT/PORT commands; - * allows override of {@link #getHostAddress()}. - * - * Useful for FTP Client behind Firewall NAT. - * - * @return __reportActiveExternalHost if non-null, else getHostAddress(); - */ - private InetAddress getReportHostAddress() { - if (__reportActiveExternalHost != null) { - return __reportActiveExternalHost; - } else { - return getHostAddress(); - } - } - - /** - * Set the client side port range in active mode. - * - * @param minPort The lowest available port (inclusive). - * @param maxPort The highest available port (inclusive). - * @since 2.2 - */ - public void setActivePortRange(int minPort, int maxPort) { - this.__activeMinPort = minPort; - this.__activeMaxPort = maxPort; - } - - /** - * Set the external IP address in active mode. - * Useful when there are multiple network cards. - * - * @param ipAddress The external IP address of this machine. - * @throws UnknownHostException if the ipAddress cannot be resolved - * @since 2.2 - */ - public void setActiveExternalIPAddress(String ipAddress) throws UnknownHostException { - this.__activeExternalHost = InetAddress.getByName(ipAddress); - } - - /** - * Set the local IP address to use in passive mode. - * Useful when there are multiple network cards. - * - * @param ipAddress The local IP address of this machine. - * @throws UnknownHostException if the ipAddress cannot be resolved - */ - public void setPassiveLocalIPAddress(String ipAddress) throws UnknownHostException { - this.__passiveLocalHost = InetAddress.getByName(ipAddress); - } - - /** - * Set the local IP address to use in passive mode. - * Useful when there are multiple network cards. - * - * @param inetAddress The local IP address of this machine. - */ - public void setPassiveLocalIPAddress(InetAddress inetAddress) { - this.__passiveLocalHost = inetAddress; - } - - /** - * Set the local IP address in passive mode. - * Useful when there are multiple network cards. - * - * @return The local IP address in passive mode. - */ - public InetAddress getPassiveLocalIPAddress() { - return this.__passiveLocalHost; - } - - /** - * Set the external IP address to report in EPRT/PORT commands in active mode. - * Useful when there are multiple network cards. - * - * @param ipAddress The external IP address of this machine. - * @throws UnknownHostException if the ipAddress cannot be resolved - * @see #getReportHostAddress() - * @since 3.1 - */ - public void setReportActiveExternalIPAddress(String ipAddress) throws UnknownHostException { - this.__reportActiveExternalHost = InetAddress.getByName(ipAddress); - } - - /** - * Sets the file type to be transferred. This should be one of - * FTP.ASCII_FILE_TYPE , FTP.BINARY_FILE_TYPE, - * etc. The file type only needs to be set when you want to change the - * type. After changing it, the new type stays in effect until you change - * it again. The default file type is FTP.ASCII_FILE_TYPE - * if this method is never called. - *
- * The server default is supposed to be ASCII (see RFC 959), however many - * ftp servers default to BINARY. To ensure correct operation with all servers, - * always specify the appropriate file type after connecting to the server. - *
- *

- * N.B. currently calling any connect method will reset the type to - * FTP.ASCII_FILE_TYPE. - * - * @param fileType The _FILE_TYPE constant indcating the - * type of file. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean setFileType(int fileType) throws IOException { - if (FTPReply.isPositiveCompletion(type(fileType))) { - __fileType = fileType; - __fileFormat = FTP.NON_PRINT_TEXT_FORMAT; - return true; - } - return false; - } - - /** - * Sets the file type to be transferred and the format. The type should be - * one of FTP.ASCII_FILE_TYPE , - * FTP.BINARY_FILE_TYPE , etc. The file type only needs to - * be set when you want to change the type. After changing it, the new - * type stays in effect until you change it again. The default file type - * is FTP.ASCII_FILE_TYPE if this method is never called. - *
- * The server default is supposed to be ASCII (see RFC 959), however many - * ftp servers default to BINARY. To ensure correct operation with all servers, - * always specify the appropriate file type after connecting to the server. - *
- * The format should be one of the FTP class TEXT_FORMAT - * constants, or if the type is FTP.LOCAL_FILE_TYPE , the - * format should be the byte size for that type. The default format - * is FTP.NON_PRINT_TEXT_FORMAT if this method is never - * called. - *

- * N.B. currently calling any connect method will reset the type to - * FTP.ASCII_FILE_TYPE and the formatOrByteSize to FTP.NON_PRINT_TEXT_FORMAT. - * - * @param fileType The _FILE_TYPE constant indcating the - * type of file. - * @param formatOrByteSize The format of the file (one of the - * _FORMAT constants. In the case of - * LOCAL_FILE_TYPE, the byte size. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean setFileType(int fileType, int formatOrByteSize) throws IOException { - if (FTPReply.isPositiveCompletion(type(fileType, formatOrByteSize))) { - __fileType = fileType; - __fileFormat = formatOrByteSize; - return true; - } - return false; - } - - /** - * Sets the file structure. The default structure is - * FTP.FILE_STRUCTURE if this method is never called - * or if a connect method is called. - * - * @param structure The structure of the file (one of the FTP class - * _STRUCTURE constants). - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean setFileStructure(int structure) throws IOException { - if (FTPReply.isPositiveCompletion(stru(structure))) { - __fileStructure = structure; - return true; - } - return false; - } - - /** - * Sets the transfer mode. The default transfer mode - * FTP.STREAM_TRANSFER_MODE if this method is never called - * or if a connect method is called. - * - * @param mode The new transfer mode to use (one of the FTP class - * _TRANSFER_MODE constants). - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean setFileTransferMode(int mode) throws IOException { - if (FTPReply.isPositiveCompletion(mode(mode))) { - __fileTransferMode = mode; - return true; - } - return false; - } - - /** - * Initiate a server to server file transfer. This method tells the - * server to which the client is connected to retrieve a given file from - * the other server. - * - * @param filename The name of the file to retrieve. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean remoteRetrieve(String filename) throws IOException { - if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE - || __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) { - return FTPReply.isPositivePreliminary(retr(filename)); - } - return false; - } - - /** - * Initiate a server to server file transfer. This method tells the - * server to which the client is connected to store a file on - * the other server using the given filename. The other server must - * have had a remoteRetrieve issued to it by another - * FTPClient. - * - * @param filename The name to call the file that is to be stored. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean remoteStore(String filename) throws IOException { - if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE - || __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) { - return FTPReply.isPositivePreliminary(stor(filename)); - } - return false; - } - - /** - * Initiate a server to server file transfer. This method tells the - * server to which the client is connected to store a file on - * the other server using a unique filename based on the given filename. - * The other server must have had a remoteRetrieve issued - * to it by another FTPClient. - * - * @param filename The name on which to base the filename of the file - * that is to be stored. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean remoteStoreUnique(String filename) throws IOException { - if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE - || __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) { - return FTPReply.isPositivePreliminary(stou(filename)); - } - return false; - } - - /** - * Initiate a server to server file transfer. This method tells the - * server to which the client is connected to store a file on - * the other server using a unique filename. - * The other server must have had a remoteRetrieve issued - * to it by another FTPClient. Many FTP servers require that a base - * filename be given from which the unique filename can be derived. For - * those servers use the other version of remoteStoreUnique - * - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean remoteStoreUnique() throws IOException { - if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE - || __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) { - return FTPReply.isPositivePreliminary(stou()); - } - return false; - } - - // For server to server transfers - - /** - * Initiate a server to server file transfer. This method tells the - * server to which the client is connected to append to a given file on - * the other server. The other server must have had a - * remoteRetrieve issued to it by another FTPClient. - * - * @param filename The name of the file to be appended to, or if the - * file does not exist, the name to call the file being stored. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean remoteAppend(String filename) throws IOException { - if (__dataConnectionMode == ACTIVE_REMOTE_DATA_CONNECTION_MODE - || __dataConnectionMode == PASSIVE_REMOTE_DATA_CONNECTION_MODE) { - return FTPReply.isPositivePreliminary(appe(filename)); - } - return false; - } - - /** - * There are a few FTPClient methods that do not complete the - * entire sequence of FTP commands to complete a transaction. These - * commands require some action by the programmer after the reception - * of a positive intermediate command. After the programmer's code - * completes its actions, it must call this method to receive - * the completion reply from the server and verify the success of the - * entire transaction. - *

- * For example, - *

-   * InputStream input;
-   * OutputStream output;
-   * input  = new FileInputStream("foobaz.txt");
-   * output = ftp.storeFileStream("foobar.txt")
-   * if(!FTPReply.isPositiveIntermediate(ftp.getReplyCode())) {
-   *     input.close();
-   *     output.close();
-   *     ftp.logout();
-   *     ftp.disconnect();
-   *     System.err.println("File transfer failed.");
-   *     System.exit(1);
-   * }
-   * Util.copyStream(input, output);
-   * input.close();
-   * output.close();
-   * // Must call completePendingCommand() to finish command.
-   * if(!ftp.completePendingCommand()) {
-   *     ftp.logout();
-   *     ftp.disconnect();
-   *     System.err.println("File transfer failed.");
-   *     System.exit(1);
-   * }
-   * 
- * - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean completePendingCommand() throws IOException { - return FTPReply.isPositiveCompletion(getReply()); - } - - /** - * Retrieves a named file from the server and writes it to the given - * OutputStream. This method does NOT close the given OutputStream. - * If the current file type is ASCII, line separators in the file are - * converted to the local representation. - *

- * Note: if you have used {@link #setRestartOffset(long)}, - * the file data will start from the selected offset. - * - * @param remote The name of the remote file. - * @param local The local OutputStream to which to write the file. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws CopyStreamException If an I/O error occurs while actually - * transferring the file. The CopyStreamException allows you to - * determine the number of bytes transferred and the IOException - * causing the error. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean retrieveFile(String remote, OutputStream local) throws IOException { - return _retrieveFile(FTPCmd.RETR.getCommand(), remote, local); - } - - /** - * @param command the command to get - * @param remote the remote file name - * @param local the local file name - * @return true if successful - * @throws IOException on error - * @since 3.1 - */ - protected boolean _retrieveFile(String command, String remote, OutputStream local) - throws IOException { - Socket socket = _openDataConnection_(command, remote); - - if (socket == null) { - return false; - } - - final InputStream input; - if (__fileType == ASCII_FILE_TYPE) { - input = new FromNetASCIIInputStream(getBufferedInputStream(socket.getInputStream())); - } else { - input = getBufferedInputStream(socket.getInputStream()); - } - - CSL csl = null; - if (__controlKeepAliveTimeout > 0) { - csl = new CSL(this, __controlKeepAliveTimeout, __controlKeepAliveReplyTimeout); - } - - // Treat everything else as binary for now - try { - Util.copyStream(input, local, getBufferSize(), CopyStreamEvent.UNKNOWN_STREAM_SIZE, - __mergeListeners(csl), false); - } finally { - Util.closeQuietly(input); - Util.closeQuietly(socket); - if (csl != null) { - csl.cleanUp(); // fetch any outstanding keepalive replies - } - } - - // Get the transfer response - boolean ok = completePendingCommand(); - return ok; - } - - /** - * Returns an InputStream from which a named file from the server - * can be read. If the current file type is ASCII, the returned - * InputStream will convert line separators in the file to - * the local representation. You must close the InputStream when you - * finish reading from it. The InputStream itself will take care of - * closing the parent data connection socket upon being closed. - *

- * To finalize the file transfer you must call - * {@link #completePendingCommand completePendingCommand } and - * check its return value to verify success. - * If this is not done, subsequent commands may behave unexpectedly. - *

- * Note: if you have used {@link #setRestartOffset(long)}, - * the file data will start from the selected offset. - * - * @param remote The name of the remote file. - * @return An InputStream from which the remote file can be read. If - * the data connection cannot be opened (e.g., the file does not - * exist), null is returned (in which case you may check the reply - * code to determine the exact reason for failure). - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public InputStream retrieveFileStream(String remote) throws IOException { - return _retrieveFileStream(FTPCmd.RETR.getCommand(), remote); - } - - /** - * @param command the command to send - * @param remote the remote file name - * @return the stream from which to read the file - * @throws IOException on error - * @since 3.1 - */ - protected InputStream _retrieveFileStream(String command, String remote) throws IOException { - Socket socket = _openDataConnection_(command, remote); - - if (socket == null) { - return null; - } - - final InputStream input; - if (__fileType == ASCII_FILE_TYPE) { - // We buffer ascii transfers because the buffering has to - // be interposed between FromNetASCIIOutputSream and the underlying - // socket input stream. We don't buffer binary transfers - // because we don't want to impose a buffering policy on the - // programmer if possible. Programmers can decide on their - // own if they want to wrap the SocketInputStream we return - // for file types other than ASCII. - input = new FromNetASCIIInputStream(getBufferedInputStream(socket.getInputStream())); - } else { - input = socket.getInputStream(); - } - return new SocketInputStream(socket, input); - } - - /** - * Stores a file on the server using the given name and taking input - * from the given InputStream. This method does NOT close the given - * InputStream. If the current file type is ASCII, line separators in - * the file are transparently converted to the NETASCII format (i.e., - * you should not attempt to create a special InputStream to do this). - * - * @param remote The name to give the remote file. - * @param local The local InputStream from which to read the file. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws CopyStreamException If an I/O error occurs while actually - * transferring the file. The CopyStreamException allows you to - * determine the number of bytes transferred and the IOException - * causing the error. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean storeFile(String remote, InputStream local) throws IOException { - return __storeFile(FTPCmd.STOR, remote, local); - } - - OnFtpInputStreamListener mListener; - - /** - * 含有事件的Ftp上传文件 - * - * @throws IOException - */ - public boolean storeFile(String remote, InputStream local, OnFtpInputStreamListener listener) - throws IOException { - mListener = listener; - return __storeFile(FTPCmd.STOR, remote, local); - } - - /** - * Returns an OutputStream through which data can be written to store - * a file on the server using the given name. If the current file type - * is ASCII, the returned OutputStream will convert line separators in - * the file to the NETASCII format (i.e., you should not attempt to - * create a special OutputStream to do this). You must close the - * OutputStream when you finish writing to it. The OutputStream itself - * will take care of closing the parent data connection socket upon being - * closed. - *

- * To finalize the file transfer you must call - * {@link #completePendingCommand completePendingCommand } and - * check its return value to verify success. - * If this is not done, subsequent commands may behave unexpectedly. - * - * @param remote The name to give the remote file. - * @return An OutputStream through which the remote file can be written. If - * the data connection cannot be opened (e.g., the file does not - * exist), null is returned (in which case you may check the reply - * code to determine the exact reason for failure). - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public OutputStream storeFileStream(String remote) throws IOException { - return __storeFileStream(FTPCmd.STOR, remote); - } - - /** - * Appends to a file on the server with the given name, taking input - * from the given InputStream. This method does NOT close the given - * InputStream. If the current file type is ASCII, line separators in - * the file are transparently converted to the NETASCII format (i.e., - * you should not attempt to create a special InputStream to do this). - * - * @param remote The name of the remote file. - * @param local The local InputStream from which to read the data to - * be appended to the remote file. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws CopyStreamException If an I/O error occurs while actually - * transferring the file. The CopyStreamException allows you to - * determine the number of bytes transferred and the IOException - * causing the error. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean appendFile(String remote, InputStream local) throws IOException { - return __storeFile(FTPCmd.APPE, remote, local); - } - - /** - * Returns an OutputStream through which data can be written to append - * to a file on the server with the given name. If the current file type - * is ASCII, the returned OutputStream will convert line separators in - * the file to the NETASCII format (i.e., you should not attempt to - * create a special OutputStream to do this). You must close the - * OutputStream when you finish writing to it. The OutputStream itself - * will take care of closing the parent data connection socket upon being - * closed. - *

- * To finalize the file transfer you must call - * {@link #completePendingCommand completePendingCommand } and - * check its return value to verify success. - * If this is not done, subsequent commands may behave unexpectedly. - * - * @param remote The name of the remote file. - * @return An OutputStream through which the remote file can be appended. - * If the data connection cannot be opened (e.g., the file does not - * exist), null is returned (in which case you may check the reply - * code to determine the exact reason for failure). - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public OutputStream appendFileStream(String remote) throws IOException { - return __storeFileStream(FTPCmd.APPE, remote); - } - - /** - * Stores a file on the server using a unique name derived from the - * given name and taking input - * from the given InputStream. This method does NOT close the given - * InputStream. If the current file type is ASCII, line separators in - * the file are transparently converted to the NETASCII format (i.e., - * you should not attempt to create a special InputStream to do this). - * - * @param remote The name on which to base the unique name given to - * the remote file. - * @param local The local InputStream from which to read the file. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws CopyStreamException If an I/O error occurs while actually - * transferring the file. The CopyStreamException allows you to - * determine the number of bytes transferred and the IOException - * causing the error. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean storeUniqueFile(String remote, InputStream local) throws IOException { - return __storeFile(FTPCmd.STOU, remote, local); - } - - /** - * Returns an OutputStream through which data can be written to store - * a file on the server using a unique name derived from the given name. - * If the current file type - * is ASCII, the returned OutputStream will convert line separators in - * the file to the NETASCII format (i.e., you should not attempt to - * create a special OutputStream to do this). You must close the - * OutputStream when you finish writing to it. The OutputStream itself - * will take care of closing the parent data connection socket upon being - * closed. - *

- * To finalize the file transfer you must call - * {@link #completePendingCommand completePendingCommand } and - * check its return value to verify success. - * If this is not done, subsequent commands may behave unexpectedly. - * - * @param remote The name on which to base the unique name given to - * the remote file. - * @return An OutputStream through which the remote file can be written. If - * the data connection cannot be opened (e.g., the file does not - * exist), null is returned (in which case you may check the reply - * code to determine the exact reason for failure). - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public OutputStream storeUniqueFileStream(String remote) throws IOException { - return __storeFileStream(FTPCmd.STOU, remote); - } - - /** - * Stores a file on the server using a unique name assigned by the - * server and taking input from the given InputStream. This method does - * NOT close the given - * InputStream. If the current file type is ASCII, line separators in - * the file are transparently converted to the NETASCII format (i.e., - * you should not attempt to create a special InputStream to do this). - * - * @param local The local InputStream from which to read the file. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws CopyStreamException If an I/O error occurs while actually - * transferring the file. The CopyStreamException allows you to - * determine the number of bytes transferred and the IOException - * causing the error. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean storeUniqueFile(InputStream local) throws IOException { - return __storeFile(FTPCmd.STOU, null, local); - } - - /** - * Returns an OutputStream through which data can be written to store - * a file on the server using a unique name assigned by the server. - * If the current file type - * is ASCII, the returned OutputStream will convert line separators in - * the file to the NETASCII format (i.e., you should not attempt to - * create a special OutputStream to do this). You must close the - * OutputStream when you finish writing to it. The OutputStream itself - * will take care of closing the parent data connection socket upon being - * closed. - *

- * To finalize the file transfer you must call - * {@link #completePendingCommand completePendingCommand } and - * check its return value to verify success. - * If this is not done, subsequent commands may behave unexpectedly. - * - * @return An OutputStream through which the remote file can be written. If - * the data connection cannot be opened (e.g., the file does not - * exist), null is returned (in which case you may check the reply - * code to determine the exact reason for failure). - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public OutputStream storeUniqueFileStream() throws IOException { - return __storeFileStream(FTPCmd.STOU, null); - } - - /** - * Reserve a number of bytes on the server for the next file transfer. - * - * @param bytes The number of bytes which the server should allocate. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean allocate(int bytes) throws IOException { - return FTPReply.isPositiveCompletion(allo(bytes)); - } - - /** - * Query the server for supported features. The server may reply with a list of server-supported - * exensions. - * For example, a typical client-server interaction might be (from RFC 2389): - *

-   * C> feat
-   * S> 211-Extensions supported:
-   * S>  MLST size*;create;modify*;perm;media-type
-   * S>  SIZE
-   * S>  COMPRESSION
-   * S>  MDTM
-   * S> 211 END
-   * 
- * - * @return True if successfully completed, false if not. - * @throws IOException on error - * @see http://www.faqs.org/rfcs/rfc2389.html - * @since 2.2 - */ - public boolean features() throws IOException { - return FTPReply.isPositiveCompletion(feat()); - } - - /** - * Query the server for a supported feature, and returns its values (if any). - * Caches the parsed response to avoid resending the command repeatedly. - * - * @param feature the feature to check - * @return if the feature is present, returns the feature values (empty array if none) - * Returns {@code null} if the feature is not found or the command failed. - * Check {@link #getReplyCode()} or {@link #getReplyString()} if so. - * @throws IOException on error - * @since 3.0 - */ - public String[] featureValues(String feature) throws IOException { - if (!initFeatureMap()) { - return null; - } - Set entries = __featuresMap.get(feature.toUpperCase(Locale.ENGLISH)); - if (entries != null) { - return entries.toArray(new String[entries.size()]); - } - return null; - } - - /** - * Query the server for a supported feature, and returns the its value (if any). - * Caches the parsed response to avoid resending the command repeatedly. - * - * @param feature the feature to check - * @return if the feature is present, returns the feature value or the empty string - * if the feature exists but has no value. - * Returns {@code null} if the feature is not found or the command failed. - * Check {@link #getReplyCode()} or {@link #getReplyString()} if so. - * @throws IOException on error - * @since 3.0 - */ - public String featureValue(String feature) throws IOException { - String[] values = featureValues(feature); - if (values != null) { - return values[0]; - } - return null; - } - - /** - * Query the server for a supported feature. - * Caches the parsed response to avoid resending the command repeatedly. - * - * @param feature the name of the feature; it is converted to upper case. - * @return {@code true} if the feature is present, {@code false} if the feature is not present - * or the {@link #feat()} command failed. Check {@link #getReplyCode()} or {@link - * #getReplyString()} - * if it is necessary to distinguish these cases. - * @throws IOException on error - * @since 3.0 - */ - public boolean hasFeature(String feature) throws IOException { - if (!initFeatureMap()) { - return false; - } - return __featuresMap.containsKey(feature.toUpperCase(Locale.ENGLISH)); - } - - /** - * Query the server for a supported feature with particular value, - * for example "AUTH SSL" or "AUTH TLS". - * Caches the parsed response to avoid resending the command repeatedly. - * - * @param feature the name of the feature; it is converted to upper case. - * @param value the value to find. - * @return {@code true} if the feature is present, {@code false} if the feature is not present - * or the {@link #feat()} command failed. Check {@link #getReplyCode()} or {@link - * #getReplyString()} - * if it is necessary to distinguish these cases. - * @throws IOException on error - * @since 3.0 - */ - public boolean hasFeature(String feature, String value) throws IOException { - if (!initFeatureMap()) { - return false; - } - Set entries = __featuresMap.get(feature.toUpperCase(Locale.ENGLISH)); - if (entries != null) { - return entries.contains(value); - } - return false; - } - - /* - * Create the feature map if not already created. - */ - private boolean initFeatureMap() throws IOException { - if (__featuresMap == null) { - // Don't create map here, because next line may throw exception - final int replyCode = feat(); - if (replyCode == FTPReply.NOT_LOGGED_IN) { // 503 - return false; // NET-518; don't create empy map - } - boolean success = FTPReply.isPositiveCompletion(replyCode); - // we init the map here, so we don't keep trying if we know the command will fail - __featuresMap = new HashMap>(); - if (!success) { - return false; - } - for (String l : getReplyStrings()) { - if (l.startsWith(" ")) { // it's a FEAT entry - String key; - String value = ""; - int varsep = l.indexOf(' ', 1); - if (varsep > 0) { - key = l.substring(1, varsep); - value = l.substring(varsep + 1); - } else { - key = l.substring(1); - } - key = key.toUpperCase(Locale.ENGLISH); - Set entries = __featuresMap.get(key); - if (entries == null) { - entries = new HashSet(); - __featuresMap.put(key, entries); - } - entries.add(value); - } - } - } - return true; - } - - /** - * Reserve space on the server for the next file transfer. - * - * @param bytes The number of bytes which the server should allocate. - * @param recordSize The size of a file record. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean allocate(int bytes, int recordSize) throws IOException { - return FTPReply.isPositiveCompletion(allo(bytes, recordSize)); - } - - /** - * Issue a command and wait for the reply. - *

- * Should only be used with commands that return replies on the - * command channel - do not use for LIST, NLST, MLSD etc. - * - * @param command The command to invoke - * @param params The parameters string, may be {@code null} - * @return True if successfully completed, false if not, in which case - * call {@link #getReplyCode()} or {@link #getReplyString()} - * to get the reason. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @since 3.0 - */ - public boolean doCommand(String command, String params) throws IOException { - return FTPReply.isPositiveCompletion(sendCommand(command, params)); - } - - /** - * Issue a command and wait for the reply, returning it as an array of strings. - *

- * Should only be used with commands that return replies on the - * command channel - do not use for LIST, NLST, MLSD etc. - * - * @param command The command to invoke - * @param params The parameters string, may be {@code null} - * @return The array of replies, or {@code null} if the command failed, in which case - * call {@link #getReplyCode()} or {@link #getReplyString()} - * to get the reason. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @since 3.0 - */ - public String[] doCommandAsStrings(String command, String params) throws IOException { - boolean success = FTPReply.isPositiveCompletion(sendCommand(command, params)); - if (success) { - return getReplyStrings(); - } else { - return null; - } - } - - /** - * Get file details using the MLST command - * - * @param pathname the file or directory to list, may be {@code null} - * @return the file details, may be {@code null} - * @throws IOException on error - * @since 3.0 - */ - public FTPFile mlistFile(String pathname) throws IOException { - boolean success = FTPReply.isPositiveCompletion(sendCommand(FTPCmd.MLST, pathname)); - if (success) { - String reply = getReplyStrings()[1]; - /* check the response makes sense. - * Must have space before fact(s) and between fact(s) and filename - * Fact(s) can be absent, so at least 3 chars are needed. - */ - if (reply.length() < 3 || reply.charAt(0) != ' ') { - throw new MalformedServerReplyException("Invalid server reply (MLST): '" + reply + "'"); - } - String entry = reply.substring(1); // skip leading space for parser - return MLSxEntryParser.parseEntry(entry); - } else { - return null; - } - } - - /** - * Generate a directory listing for the current directory using the MLSD command. - * - * @return the array of file entries - * @throws IOException on error - * @since 3.0 - */ - public FTPFile[] mlistDir() throws IOException { - return mlistDir(null); - } - - /** - * Generate a directory listing using the MLSD command. - * - * @param pathname the directory name, may be {@code null} - * @return the array of file entries - * @throws IOException on error - * @since 3.0 - */ - public FTPFile[] mlistDir(String pathname) throws IOException { - FTPListParseEngine engine = initiateMListParsing(pathname); - return engine.getFiles(); - } - - /** - * Generate a directory listing using the MLSD command. - * - * @param pathname the directory name, may be {@code null} - * @param filter the filter to apply to the responses - * @return the array of file entries - * @throws IOException on error - * @since 3.0 - */ - public FTPFile[] mlistDir(String pathname, FTPFileFilter filter) throws IOException { - FTPListParseEngine engine = initiateMListParsing(pathname); - return engine.getFiles(filter); - } - - /** - * Restart a STREAM_TRANSFER_MODE file transfer starting - * from the given offset. This will only work on FTP servers supporting - * the REST comand for the stream transfer mode. However, most FTP - * servers support this. Any subsequent file transfer will start - * reading or writing the remote file from the indicated offset. - * - * @param offset The offset into the remote file at which to start the - * next file transfer. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @since 3.1 (changed from private to protected) - */ - protected boolean restart(long offset) throws IOException { - __restartOffset = 0; - return FTPReply.isPositiveIntermediate(rest(Long.toString(offset))); - } - - /** - * Sets the restart offset for file transfers. - *

- * The restart command is not sent to the server immediately. - * It is sent when a data connection is created as part of a - * subsequent command. - * The restart marker is reset to zero after use. - *

- *

- * Note: This method should only be invoked immediately prior to - * the transfer to which it applies. - * - * @param offset The offset into the remote file at which to start the - * next file transfer. This must be a value greater than or - * equal to zero. - */ - public void setRestartOffset(long offset) { - if (offset >= 0) { - __restartOffset = offset; - } - } - - /** - * Fetches the restart offset. - * - * @return offset The offset into the remote file at which to start the - * next file transfer. - */ - public long getRestartOffset() { - return __restartOffset; - } - - /** - * Renames a remote file. - * - * @param from The name of the remote file to rename. - * @param to The new name of the remote file. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean rename(String from, String to) throws IOException { - if (!FTPReply.isPositiveIntermediate(rnfr(from))) { - return false; - } - - return FTPReply.isPositiveCompletion(rnto(to)); - } - - /** - * Abort a transfer in progress. - * - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean abort() throws IOException { - return FTPReply.isPositiveCompletion(abor()); - } - - /** - * Deletes a file on the FTP server. - * - * @param pathname The pathname of the file to be deleted. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean deleteFile(String pathname) throws IOException { - return FTPReply.isPositiveCompletion(dele(pathname)); - } - - /** - * Removes a directory on the FTP server (if empty). - * - * @param pathname The pathname of the directory to remove. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean removeDirectory(String pathname) throws IOException { - return FTPReply.isPositiveCompletion(rmd(pathname)); - } - - /** - * Creates a new subdirectory on the FTP server in the current directory - * (if a relative pathname is given) or where specified (if an absolute - * pathname is given). - * - * @param pathname The pathname of the directory to create. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean makeDirectory(String pathname) throws IOException { - return FTPReply.isPositiveCompletion(mkd(pathname)); - } - - /** - * Returns the pathname of the current working directory. - * - * @return The pathname of the current working directory. If it cannot - * be obtained, returns null. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public String printWorkingDirectory() throws IOException { - if (pwd() != FTPReply.PATHNAME_CREATED) { - return null; - } - - return __parsePathname(_replyLines.get(_replyLines.size() - 1)); - } - - /** - * Send a site specific command. - * - * @param arguments The site specific command and arguments. - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean sendSiteCommand(String arguments) throws IOException { - return FTPReply.isPositiveCompletion(site(arguments)); - } - - /** - * Fetches the system type from the server and returns the string. - * This value is cached for the duration of the connection after the - * first call to this method. In other words, only the first time - * that you invoke this method will it issue a SYST command to the - * FTP server. FTPClient will remember the value and return the - * cached value until a call to disconnect. - *

- * If the SYST command fails, and the system property - * {@link #FTP_SYSTEM_TYPE_DEFAULT} is defined, then this is used instead. - * - * @return The system type obtained from the server. Never null. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server (and the default - * system type property is not defined) - * @since 2.2 - */ - public String getSystemType() throws IOException { - //if (syst() == FTPReply.NAME_SYSTEM_TYPE) - // Technically, we should expect a NAME_SYSTEM_TYPE response, but - // in practice FTP servers deviate, so we soften the condition to - // a positive completion. - if (__systemName == null) { - if (FTPReply.isPositiveCompletion(syst())) { - // Assume that response is not empty here (cannot be null) - __systemName = _replyLines.get(_replyLines.size() - 1).substring(4); - } else { - // Check if the user has provided a default for when the SYST command fails - String systDefault = System.getProperty(FTP_SYSTEM_TYPE_DEFAULT); - if (systDefault != null) { - __systemName = systDefault; - } else { - throw new IOException("Unable to determine system type - response: " + getReplyString()); - } - } - } - return __systemName; - } - - /** - * Fetches the system help information from the server and returns the - * full string. - * - * @return The system help string obtained from the server. null if the - * information could not be obtained. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public String listHelp() throws IOException { - if (FTPReply.isPositiveCompletion(help())) { - return getReplyString(); - } - return null; - } - - /** - * Fetches the help information for a given command from the server and - * returns the full string. - * - * @param command The command on which to ask for help. - * @return The command help string obtained from the server. null if the - * information could not be obtained. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public String listHelp(String command) throws IOException { - if (FTPReply.isPositiveCompletion(help(command))) { - return getReplyString(); - } - return null; - } - - /** - * Sends a NOOP command to the FTP server. This is useful for preventing - * server timeouts. - * - * @return True if successfully completed, false if not. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public boolean sendNoOp() throws IOException { - return FTPReply.isPositiveCompletion(noop()); - } - - /** - * Obtain a list of filenames in a directory (or just the name of a given - * file, which is not particularly useful). This information is obtained - * through the NLST command. If the given pathname is a directory and - * contains no files, a zero length array is returned only - * if the FTP server returned a positive completion code, otherwise - * null is returned (the FTP server returned a 550 error No files found.). - * If the directory is not empty, an array of filenames in the directory is - * returned. If the pathname corresponds - * to a file, only that file will be listed. The server may or may not - * expand glob expressions. - * - * @param pathname The file or directory to list. - * Warning: the server may treat a leading '-' as an - * option introducer. If so, try using an absolute path, - * or prefix the path with ./ (unix style servers). - * Some servers may support "--" as meaning end of options, - * in which case "-- -xyz" should work. - * @return The list of filenames contained in the given path. null if - * the list could not be obtained. If there are no filenames in - * the directory, a zero-length array is returned. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public String[] listNames(String pathname) throws IOException { - Socket socket = _openDataConnection_(FTPCmd.NLST, getListArguments(pathname)); - - if (socket == null) { - return null; - } - - BufferedReader reader = - new BufferedReader(new InputStreamReader(socket.getInputStream(), getControlEncoding())); - - ArrayList results = new ArrayList(); - String line; - while ((line = reader.readLine()) != null) { - results.add(line); - } - - reader.close(); - socket.close(); - - if (completePendingCommand()) { - String[] names = new String[results.size()]; - return results.toArray(names); - } - - return null; - } - - /** - * Obtain a list of filenames in the current working directory - * This information is obtained through the NLST command. If the current - * directory contains no files, a zero length array is returned only - * if the FTP server returned a positive completion code, otherwise, - * null is returned (the FTP server returned a 550 error No files found.). - * If the directory is not empty, an array of filenames in the directory is - * returned. - * - * @return The list of filenames contained in the current working - * directory. null if the list could not be obtained. - * If there are no filenames in the directory, a zero-length array - * is returned. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public String[] listNames() throws IOException { - return listNames(null); - } - - /** - * Using the default system autodetect mechanism, obtain a - * list of file information for the current working directory - * or for just a single file. - *

- * This information is obtained through the LIST command. The contents of - * the returned array is determined by the FTPFileEntryParser - * used. - *

- * N.B. the LIST command does not generally return very precise timestamps. - * For recent files, the response usually contains hours and minutes (not seconds). - * For older files, the output may only contain a date. - * If the server supports it, the MLSD command returns timestamps with a precision - * of seconds, and may include milliseconds. See {@link #mlistDir()} - * - * @param pathname The file or directory to list. Since the server may - * or may not expand glob expressions, using them here - * is not recommended and may well cause this method to - * fail. - * Also, some servers treat a leading '-' as being an option. - * To avoid this interpretation, use an absolute pathname - * or prefix the pathname with ./ (unix style servers). - * Some servers may support "--" as meaning end of options, - * in which case "-- -xyz" should work. - * @return The list of file information contained in the given path in - * the format determined by the autodetection mechanism - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection - * as a result of the client being idle or some other - * reason causing the server to send FTP reply code 421. - * This exception may be caught either as an IOException - * or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply - * from the server. - * @throws ParserInitializationException Thrown if the - * parserKey - * parameter cannot be - * resolved by the selected parser factory. - * In the DefaultFTPEntryParserFactory, this will - * happen when parserKey is neither - * the fully qualified class name of a class - * implementing the interface - * FTPFileEntryParser - * nor a string containing one of the recognized keys - * mapping to such a parser or if class loader - * security issues prevent its being loaded. - * @see DefaultFTPFileEntryParserFactory - * @see FTPFileEntryParserFactory - * @see FTPFileEntryParser - */ - public FTPFile[] listFiles(String pathname) throws IOException { - FTPListParseEngine engine = initiateListParsing((String) null, pathname); - return engine.getFiles(); - } - - /** - * Using the default system autodetect mechanism, obtain a - * list of file information for the current working directory. - *

- * This information is obtained through the LIST command. The contents of - * the returned array is determined by the FTPFileEntryParser - * used. - *

- * N.B. the LIST command does not generally return very precise timestamps. - * For recent files, the response usually contains hours and minutes (not seconds). - * For older files, the output may only contain a date. - * If the server supports it, the MLSD command returns timestamps with a precision - * of seconds, and may include milliseconds. See {@link #mlistDir()} - * - * @return The list of file information contained in the current directory - * in the format determined by the autodetection mechanism. - *

- * NOTE: This array may contain null members if any of the - * individual file listings failed to parse. The caller should - * check each entry for null before referencing it. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection - * as a result of the client being idle or some other - * reason causing the server to send FTP reply code 421. - * This exception may be caught either as an IOException - * or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply - * from the server. - * @throws ParserInitializationException Thrown if the - * parserKey - * parameter cannot be - * resolved by the selected parser factory. - * In the DefaultFTPEntryParserFactory, this will - * happen when parserKey is neither - * the fully qualified class name of a class - * implementing the interface - * FTPFileEntryParser - * nor a string containing one of the recognized keys - * mapping to such a parser or if class loader - * security issues prevent its being loaded. - * @see DefaultFTPFileEntryParserFactory - * @see FTPFileEntryParserFactory - * @see FTPFileEntryParser - */ - public FTPFile[] listFiles() throws IOException { - return listFiles((String) null); - } - - /** - * Version of {@link #listFiles(String)} which allows a filter to be provided. - * For example: listFiles("site", FTPFileFilters.DIRECTORY); - * - * @param pathname the initial path, may be null - * @param filter the filter, non-null - * @return the list of FTPFile entries. - * @throws IOException on error - * @since 2.2 - */ - public FTPFile[] listFiles(String pathname, FTPFileFilter filter) throws IOException { - FTPListParseEngine engine = initiateListParsing((String) null, pathname); - return engine.getFiles(filter); - } - - /** - * Using the default system autodetect mechanism, obtain a - * list of directories contained in the current working directory. - *

- * This information is obtained through the LIST command. The contents of - * the returned array is determined by the FTPFileEntryParser - * used. - *

- * N.B. the LIST command does not generally return very precise timestamps. - * For recent files, the response usually contains hours and minutes (not seconds). - * For older files, the output may only contain a date. - * If the server supports it, the MLSD command returns timestamps with a precision - * of seconds, and may include milliseconds. See {@link #mlistDir()} - * - * @return The list of directories contained in the current directory - * in the format determined by the autodetection mechanism. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection - * as a result of the client being idle or some other - * reason causing the server to send FTP reply code 421. - * This exception may be caught either as an IOException - * or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply - * from the server. - * @throws ParserInitializationException Thrown if the - * parserKey - * parameter cannot be - * resolved by the selected parser factory. - * In the DefaultFTPEntryParserFactory, this will - * happen when parserKey is neither - * the fully qualified class name of a class - * implementing the interface - * FTPFileEntryParser - * nor a string containing one of the recognized keys - * mapping to such a parser or if class loader - * security issues prevent its being loaded. - * @see DefaultFTPFileEntryParserFactory - * @see FTPFileEntryParserFactory - * @see FTPFileEntryParser - * @since 3.0 - */ - public FTPFile[] listDirectories() throws IOException { - return listDirectories((String) null); - } - - /** - * Using the default system autodetect mechanism, obtain a - * list of directories contained in the specified directory. - *

- * This information is obtained through the LIST command. The contents of - * the returned array is determined by the FTPFileEntryParser - * used. - *

- * N.B. the LIST command does not generally return very precise timestamps. - * For recent files, the response usually contains hours and minutes (not seconds). - * For older files, the output may only contain a date. - * If the server supports it, the MLSD command returns timestamps with a precision - * of seconds, and may include milliseconds. See {@link #mlistDir()} - * - * @param parent the starting directory - * @return The list of directories contained in the specified directory - * in the format determined by the autodetection mechanism. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection - * as a result of the client being idle or some other - * reason causing the server to send FTP reply code 421. - * This exception may be caught either as an IOException - * or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply - * from the server. - * @throws ParserInitializationException Thrown if the - * parserKey - * parameter cannot be - * resolved by the selected parser factory. - * In the DefaultFTPEntryParserFactory, this will - * happen when parserKey is neither - * the fully qualified class name of a class - * implementing the interface - * FTPFileEntryParser - * nor a string containing one of the recognized keys - * mapping to such a parser or if class loader - * security issues prevent its being loaded. - * @see DefaultFTPFileEntryParserFactory - * @see FTPFileEntryParserFactory - * @see FTPFileEntryParser - * @since 3.0 - */ - public FTPFile[] listDirectories(String parent) throws IOException { - return listFiles(parent, FTPFileFilters.DIRECTORIES); - } - - /** - * Using the default autodetect mechanism, initialize an FTPListParseEngine - * object containing a raw file information for the current working - * directory on the server - * This information is obtained through the LIST command. This object - * is then capable of being iterated to return a sequence of FTPFile - * objects with information filled in by the - * FTPFileEntryParser used. - *

- * This method differs from using the listFiles() methods in that - * expensive FTPFile objects are not created until needed which may be - * an advantage on large lists. - * - * @return A FTPListParseEngine object that holds the raw information and - * is capable of providing parsed FTPFile objects, one for each file - * containing information contained in the given path in the format - * determined by the parser parameter. Null will be - * returned if a data connection cannot be opened. If the current working - * directory contains no files, an empty array will be the return. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @throws ParserInitializationException Thrown if the - * autodetect mechanism cannot - * resolve the type of system we are connected with. - * @see FTPListParseEngine - */ - public FTPListParseEngine initiateListParsing() throws IOException { - return initiateListParsing((String) null); - } - - /** - * Using the default autodetect mechanism, initialize an FTPListParseEngine - * object containing a raw file information for the supplied directory. - * This information is obtained through the LIST command. This object - * is then capable of being iterated to return a sequence of FTPFile - * objects with information filled in by the - * FTPFileEntryParser used. - *

- * The server may or may not expand glob expressions. You should avoid - * using glob expressions because the return format for glob listings - * differs from server to server and will likely cause this method to fail. - *

- * This method differs from using the listFiles() methods in that - * expensive FTPFile objects are not created until needed which may be - * an advantage on large lists. - * - *

-   *    FTPClient f=FTPClient();
-   *    f.connect(server);
-   *    f.login(username, password);
-   *    FTPListParseEngine engine = f.initiateListParsing(directory);
-   *
-   *    while (engine.hasNext()) {
-   *       FTPFile[] files = engine.getNext(25);  // "page size" you want
-   *       //do whatever you want with these files, display them, etc.
-   *       //expensive FTPFile objects not created until needed.
-   *    }
-   * 
- * - * @param pathname the starting directory - * @return A FTPListParseEngine object that holds the raw information and - * is capable of providing parsed FTPFile objects, one for each file - * containing information contained in the given path in the format - * determined by the parser parameter. Null will be - * returned if a data connection cannot be opened. If the current working - * directory contains no files, an empty array will be the return. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @throws ParserInitializationException Thrown if the - * autodetect mechanism cannot - * resolve the type of system we are connected with. - * @see FTPListParseEngine - */ - public FTPListParseEngine initiateListParsing(String pathname) throws IOException { - return initiateListParsing((String) null, pathname); - } - - /** - * Using the supplied parser key, initialize an FTPListParseEngine - * object containing a raw file information for the supplied directory. - * This information is obtained through the LIST command. This object - * is then capable of being iterated to return a sequence of FTPFile - * objects with information filled in by the - * FTPFileEntryParser used. - *

- * The server may or may not expand glob expressions. You should avoid - * using glob expressions because the return format for glob listings - * differs from server to server and will likely cause this method to fail. - *

- * This method differs from using the listFiles() methods in that - * expensive FTPFile objects are not created until needed which may be - * an advantage on large lists. - * - * @param parserKey A string representing a designated code or fully-qualified - * class name of an FTPFileEntryParser that should be - * used to parse each server file listing. - * May be {@code null}, in which case the code checks first - * the system property {@link #FTP_SYSTEM_TYPE}, and if that is - * not defined the SYST command is used to provide the value. - * To allow for arbitrary system types, the return from the - * SYST command is used to look up an alias for the type in the - * {@link #SYSTEM_TYPE_PROPERTIES} properties file if it is available. - * @param pathname the starting directory - * @return A FTPListParseEngine object that holds the raw information and - * is capable of providing parsed FTPFile objects, one for each file - * containing information contained in the given path in the format - * determined by the parser parameter. Null will be - * returned if a data connection cannot be opened. If the current working - * directory contains no files, an empty array will be the return. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @throws ParserInitializationException Thrown if the - * parserKey - * parameter cannot be - * resolved by the selected parser factory. - * In the DefaultFTPEntryParserFactory, this will - * happen when parserKey is neither - * the fully qualified class name of a class - * implementing the interface - * FTPFileEntryParser - * nor a string containing one of the recognized keys - * mapping to such a parser or if class loader - * security issues prevent its being loaded. - * @see FTPListParseEngine - */ - public FTPListParseEngine initiateListParsing(String parserKey, String pathname) - throws IOException { - __createParser(parserKey); // create and cache parser - return initiateListParsing(__entryParser, pathname); - } - - // package access for test purposes - void __createParser(String parserKey) throws IOException { - // We cache the value to avoid creation of a new object every - // time a file listing is generated. - // Note: we don't check against a null parserKey (NET-544) - if (__entryParser == null || (parserKey != null && !__entryParserKey.equals(parserKey))) { - if (null != parserKey) { - // if a parser key was supplied in the parameters, - // use that to create the parser - __entryParser = __parserFactory.createFileEntryParser(parserKey); - __entryParserKey = parserKey; - } else { - // if no parserKey was supplied, check for a configuration - // in the params, and if it has a non-empty system type, use that. - if (null != __configuration && __configuration.getServerSystemKey().length() > 0) { - __entryParser = __parserFactory.createFileEntryParser(__configuration); - __entryParserKey = __configuration.getServerSystemKey(); - } else { - // if a parserKey hasn't been supplied, and a configuration - // hasn't been supplied, and the override property is not set - // then autodetect by calling - // the SYST command and use that to choose the parser. - String systemType = System.getProperty(FTP_SYSTEM_TYPE); - if (systemType == null) { - systemType = getSystemType(); // cannot be null - Properties override = getOverrideProperties(); - if (override != null) { - String newType = override.getProperty(systemType); - if (newType != null) { - systemType = newType; - } - } - } - if (null != __configuration) { // system type must have been empty above - __entryParser = __parserFactory.createFileEntryParser( - new FTPClientConfig(systemType, __configuration)); - } else { - __entryParser = __parserFactory.createFileEntryParser(systemType); - } - __entryParserKey = systemType; - } - } - } - } - - /** - * private method through which all listFiles() and - * initiateListParsing methods pass once a parser is determined. - * - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - * @see FTPListParseEngine - */ - private FTPListParseEngine initiateListParsing(FTPFileEntryParser parser, String pathname) - throws IOException { - Socket socket = _openDataConnection_(FTPCmd.LIST, getListArguments(pathname)); - - FTPListParseEngine engine = new FTPListParseEngine(parser, __configuration); - if (socket == null) { - return engine; - } - - try { - engine.readServerList(socket.getInputStream(), getControlEncoding()); - } finally { - Util.closeQuietly(socket); - } - - completePendingCommand(); - return engine; - } - - /** - * Initiate list parsing for MLSD listings. - * - * @return the engine - * @throws IOException - */ - private FTPListParseEngine initiateMListParsing(String pathname) throws IOException { - Socket socket = _openDataConnection_(FTPCmd.MLSD, pathname); - FTPListParseEngine engine = - new FTPListParseEngine(MLSxEntryParser.getInstance(), __configuration); - if (socket == null) { - return engine; - } - - try { - engine.readServerList(socket.getInputStream(), getControlEncoding()); - } finally { - Util.closeQuietly(socket); - completePendingCommand(); - } - return engine; - } - - /** - * @param pathname the initial pathname - * @return the adjusted string with "-a" added if necessary - * @since 2.0 - */ - protected String getListArguments(String pathname) { - if (getListHiddenFiles()) { - if (pathname != null) { - StringBuilder sb = new StringBuilder(pathname.length() + 3); - sb.append("-a "); - sb.append(pathname); - return sb.toString(); - } else { - return "-a"; - } - } - - return pathname; - } - - /** - * Issue the FTP STAT command to the server. - * - * @return The status information returned by the server. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public String getStatus() throws IOException { - if (FTPReply.isPositiveCompletion(stat())) { - return getReplyString(); - } - return null; - } - - /** - * Issue the FTP STAT command to the server for a given pathname. This - * should produce a listing of the file or directory. - * - * @param pathname the filename - * @return The status information returned by the server. - * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a - * result - * of the client being idle or some other reason causing the server - * to send FTP reply code 421. This exception may be caught either - * as an IOException or independently as itself. - * @throws IOException If an I/O error occurs while either sending a - * command to the server or receiving a reply from the server. - */ - public String getStatus(String pathname) throws IOException { - if (FTPReply.isPositiveCompletion(stat(pathname))) { - return getReplyString(); - } - return null; - } - - /** - * Issue the FTP MDTM command (not supported by all servers) to retrieve the last - * modification time of a file. The modification string should be in the - * ISO 3077 form "YYYYMMDDhhmmss(.xxx)?". The timestamp represented should also be in - * GMT, but not all FTP servers honour this. - * - * @param pathname The file path to query. - * @return A string representing the last file modification time in YYYYMMDDhhmmss - * format. - * @throws IOException if an I/O error occurs. - * @since 2.0 - */ - public String getModificationTime(String pathname) throws IOException { - if (FTPReply.isPositiveCompletion(mdtm(pathname))) { - return getReplyStrings()[0].substring(4); // skip the return code (e.g. 213) and the space - } - return null; - } - - /** - * Issue the FTP MDTM command (not supported by all servers) to retrieve the last - * modification time of a file. The modification string should be in the - * ISO 3077 form "YYYYMMDDhhmmss(.xxx)?". The timestamp represented should also be in - * GMT, but not all FTP servers honour this. - * - * @param pathname The file path to query. - * @return A FTPFile representing the last file modification time, may be {@code null}. - * The FTPFile timestamp will be null if a parse error occurs. - * @throws IOException if an I/O error occurs. - * @since 3.4 - */ - public FTPFile mdtmFile(String pathname) throws IOException { - if (FTPReply.isPositiveCompletion(mdtm(pathname))) { - String reply = - getReplyStrings()[0].substring(4); // skip the return code (e.g. 213) and the space - FTPFile file = new FTPFile(); - file.setName(pathname); - file.setRawListing(reply); - file.setTimestamp(MLSxEntryParser.parseGMTdateTime(reply)); - return file; - } - return null; - } - - /** - * Issue the FTP MFMT command (not supported by all servers) which sets the last - * modified time of a file. - * - * The timestamp should be in the form YYYYMMDDhhmmss. It should also - * be in GMT, but not all servers honour this. - * - * An FTP server would indicate its support of this feature by including "MFMT" - * in its response to the FEAT command, which may be retrieved by FTPClient.features() - * - * @param pathname The file path for which last modified time is to be changed. - * @param timeval The timestamp to set to, in YYYYMMDDhhmmss format. - * @return true if successfully set, false if not - * @throws IOException if an I/O error occurs. - * @see http://tools.ietf.org/html/draft-somers-ftp-mfxx-04 - * @since 2.2 - */ - public boolean setModificationTime(String pathname, String timeval) throws IOException { - return (FTPReply.isPositiveCompletion(mfmt(pathname, timeval))); - } - - /** - * Set the internal buffer size for buffered data streams. - * - * @param bufSize The size of the buffer. Use a non-positive value to use the default. - */ - public void setBufferSize(int bufSize) { - __bufferSize = bufSize; - } - - /** - * Retrieve the current internal buffer size for buffered data streams. - * - * @return The current buffer size. - */ - public int getBufferSize() { - return __bufferSize; - } - - /** - * Sets the value to be used for the data socket SO_SNDBUF option. - * If the value is positive, the option will be set when the data socket has been created. - * - * @param bufSize The size of the buffer, zero or negative means the value is ignored. - * @since 3.3 - */ - public void setSendDataSocketBufferSize(int bufSize) { - __sendDataSocketBufferSize = bufSize; - } - - /** - * Retrieve the value to be used for the data socket SO_SNDBUF option. - * - * @return The current buffer size. - * @since 3.3 - */ - public int getSendDataSocketBufferSize() { - return __sendDataSocketBufferSize; - } - - /** - * Sets the value to be used for the data socket SO_RCVBUF option. - * If the value is positive, the option will be set when the data socket has been created. - * - * @param bufSize The size of the buffer, zero or negative means the value is ignored. - * @since 3.3 - */ - public void setReceieveDataSocketBufferSize(int bufSize) { - __receiveDataSocketBufferSize = bufSize; - } - - /** - * Retrieve the value to be used for the data socket SO_RCVBUF option. - * - * @return The current buffer size. - * @since 3.3 - */ - public int getReceiveDataSocketBufferSize() { - return __receiveDataSocketBufferSize; - } - - /** - * Implementation of the {@link Configurable Configurable} interface. - * In the case of this class, configuring merely makes the config object available for the - * factory methods that construct parsers. - * - * @param config {@link FTPClientConfig FTPClientConfig} object used to - * provide non-standard configurations to the parser. - * @since 1.4 - */ - @Override public void configure(FTPClientConfig config) { - this.__configuration = config; - } - - /** - * You can set this to true if you would like to get hidden files when {@link #listFiles} too. - * A LIST -a will be issued to the ftp server. - * It depends on your ftp server if you need to call this method, also dont expect to get rid - * of hidden files if you call this method with "false". - * - * @param listHiddenFiles true if hidden files should be listed - * @since 2.0 - */ - public void setListHiddenFiles(boolean listHiddenFiles) { - this.__listHiddenFiles = listHiddenFiles; - } - - /** - * @return the current state - * @see #setListHiddenFiles(boolean) - * @since 2.0 - */ - public boolean getListHiddenFiles() { - return this.__listHiddenFiles; - } - - /** - * Whether should attempt to use EPSV with IPv4. - * Default (if not set) is false - * - * @return true if should attempt EPSV - * @since 2.2 - */ - public boolean isUseEPSVwithIPv4() { - return __useEPSVwithIPv4; - } - - /** - * Set whether to use EPSV with IPv4. - * Might be worth enabling in some circumstances. - * - * For example, when using IPv4 with NAT it - * may work with some rare configurations. - * E.g. if FTP server has a static PASV address (external network) - * and the client is coming from another internal network. - * In that case the data connection after PASV command would fail, - * while EPSV would make the client succeed by taking just the port. - * - * @param selected value to set. - * @since 2.2 - */ - public void setUseEPSVwithIPv4(boolean selected) { - this.__useEPSVwithIPv4 = selected; - } - - /** - * Set the listener to be used when performing store/retrieve operations. - * The default value (if not set) is {@code null}. - * - * @param listener to be used, may be {@code null} to disable - * @since 3.0 - */ - public void setCopyStreamListener(CopyStreamListener listener) { - __copyStreamListener = listener; - } - - /** - * Obtain the currently active listener. - * - * @return the listener, may be {@code null} - * @since 3.0 - */ - public CopyStreamListener getCopyStreamListener() { - return __copyStreamListener; - } - - /** - * Set the time to wait between sending control connection keepalive messages - * when processing file upload or download. - * - * @param controlIdle the wait (in secs) between keepalive messages. Zero (or less) disables. - * @see #setControlKeepAliveReplyTimeout(int) - * @since 3.0 - */ - public void setControlKeepAliveTimeout(long controlIdle) { - __controlKeepAliveTimeout = controlIdle * 1000; - } - - /** - * Get the time to wait between sending control connection keepalive messages. - * - * @return the number of seconds between keepalive messages. - * @since 3.0 - */ - public long getControlKeepAliveTimeout() { - return __controlKeepAliveTimeout / 1000; - } - - /** - * Set how long to wait for control keep-alive message replies. - * - * @param timeout number of milliseconds to wait (defaults to 1000) - * @see #setControlKeepAliveTimeout(long) - * @since 3.0 - */ - public void setControlKeepAliveReplyTimeout(int timeout) { - __controlKeepAliveReplyTimeout = timeout; - } - - /** - * Get how long to wait for control keep-alive message replies. - * - * @return wait time in msec - * @since 3.0 - */ - public int getControlKeepAliveReplyTimeout() { - return __controlKeepAliveReplyTimeout; - } - - /** - * Enable or disable passive mode NAT workaround. - * If enabled, a site-local PASV mode reply address will be replaced with the - * remote host address to which the PASV mode request was sent - * (unless that is also a site local address). - * This gets around the problem that some NAT boxes may change the - * reply. - * - * The default is true, i.e. site-local replies are replaced. - * - * @param enabled true to enable replacing internal IP's in passive - * mode. - * @deprecated (3.6) use {@link #setPassiveNatWorkaroundStrategy(HostnameResolver)} instead - */ - @Deprecated public void setPassiveNatWorkaround(boolean enabled) { - if (enabled) { - this.__passiveNatWorkaroundStrategy = new NatServerResolverImpl(this); - } else { - this.__passiveNatWorkaroundStrategy = null; - } - } - - /** - * Set the workaround strategy to replace the PASV mode reply addresses. - * This gets around the problem that some NAT boxes may change the reply. - * - * The default implementation is {@code NatServerResolverImpl}, i.e. site-local - * replies are replaced. - * - * @param resolver strategy to replace internal IP's in passive mode - * or null to disable the workaround (i.e. use PASV mode reply address.) - * @since 3.6 - */ - public void setPassiveNatWorkaroundStrategy(HostnameResolver resolver) { - this.__passiveNatWorkaroundStrategy = resolver; - } - - /** - * Strategy interface for updating host names received from FTP server - * for passive NAT workaround. - * - * @since 3.6 - */ - public static interface HostnameResolver { - String resolve(String hostname) throws UnknownHostException; - } - - /** - * Default strategy for passive NAT workaround (site-local - * replies are replaced.) - * - * @since 3.6 - */ - public static class NatServerResolverImpl implements HostnameResolver { - private FTPClient client; - - public NatServerResolverImpl(FTPClient client) { - this.client = client; - } - - @Override public String resolve(String hostname) throws UnknownHostException { - String newHostname = hostname; - InetAddress host = InetAddress.getByName(newHostname); - // reply is a local address, but target is not - assume NAT box changed the PASV reply - if (host.isSiteLocalAddress()) { - InetAddress remote = this.client.getRemoteAddress(); - if (!remote.isSiteLocalAddress()) { - newHostname = remote.getHostAddress(); - } - } - return newHostname; - } - } - - private OutputStream getBufferedOutputStream(OutputStream outputStream) { - if (__bufferSize > 0) { - return new BufferedOutputStream(outputStream, __bufferSize); - } - return new BufferedOutputStream(outputStream); - } - - private InputStream getBufferedInputStream(InputStream inputStream) { - if (__bufferSize > 0) { - return new BufferedInputStream(inputStream, __bufferSize); - } - return new BufferedInputStream(inputStream); - } - - // @since 3.0 - private static class CSL implements CopyStreamListener { - - private final FTPClient parent; - private final long idle; - private final int currentSoTimeout; - - private long time = System.currentTimeMillis(); - private int notAcked; - private OnFtpInputStreamListener listener; - private long lTime = time; - - CSL(FTPClient parent, long idleTime, int maxWait) throws SocketException { - this(parent, idleTime, maxWait, null); - } - - CSL(FTPClient parent, long idleTime, int maxWait, OnFtpInputStreamListener listener) - throws SocketException { - this.idle = idleTime; - this.parent = parent; - this.currentSoTimeout = parent.getSoTimeout(); - parent.setSoTimeout(maxWait); - this.listener = listener; - } - - @Override public void bytesTransferred(CopyStreamEvent event) { - bytesTransferred(event.getTotalBytesTransferred(), event.getBytesTransferred(), - event.getStreamSize()); - } - - @Override public void bytesTransferred(long totalBytesTransferred, int bytesTransferred, - long streamSize) { - long now = System.currentTimeMillis(); - if (now - time > idle) { - try { - parent.__noop(); - } catch (SocketTimeoutException e) { - notAcked++; - } catch (IOException e) { - // Ignored - } - - time = now; - } - //if (now - lTime > 100) { - if (listener != null) { - listener.onFtpInputStream(parent, totalBytesTransferred, bytesTransferred, streamSize); - } - //lTime = now; - //} - } - - void cleanUp() throws IOException { - try { - while (notAcked-- > 0) { - parent.__getReplyNoReport(); - } - } finally { - parent.setSoTimeout(currentSoTimeout); - } - } - } - - /** - * Merge two copystream listeners, either or both of which may be null. - * - * @param local the listener used by this class, may be null - * @return a merged listener or a single listener or null - * @since 3.0 - */ - private CopyStreamListener __mergeListeners(CopyStreamListener local) { - if (local == null) { - return __copyStreamListener; - } - if (__copyStreamListener == null) { - return local; - } - // Both are non-null - CopyStreamAdapter merged = new CopyStreamAdapter(); - merged.addCopyStreamListener(local); - merged.addCopyStreamListener(__copyStreamListener); - return merged; - } - - /** - * Enables or disables automatic server encoding detection (only UTF-8 supported). - *

- * Does not affect existing connections; must be invoked before a connection is established. - * - * @param autodetect If true, automatic server encoding detection will be enabled. - */ - public void setAutodetectUTF8(boolean autodetect) { - __autodetectEncoding = autodetect; - } - - /** - * Tells if automatic server encoding detection is enabled or disabled. - * - * @return true, if automatic server encoding detection is enabled. - */ - public boolean getAutodetectUTF8() { - return __autodetectEncoding; - } - - // Method for use by unit test code only - FTPFileEntryParser getEntryParser() { - return __entryParser; - } - - // DEPRECATED METHODS - for API compatibility only - DO NOT USE - - /** - * @return the name - * @throws IOException on error - * @deprecated use {@link #getSystemType()} instead - */ - @Deprecated public String getSystemName() throws IOException { - if (__systemName == null && FTPReply.isPositiveCompletion(syst())) { - __systemName = _replyLines.get(_replyLines.size() - 1).substring(4); - } - return __systemName; - } -} - -/* Emacs configuration - * Local variables: ** - * mode: java ** - * c-basic-offset: 4 ** - * indent-tabs-mode: nil ** - * End: ** - */ -/* kate: indent-width 4; replace-tabs on; */ diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPClientConfig.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPClientConfig.java deleted file mode 100644 index abe8902e..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPClientConfig.java +++ /dev/null @@ -1,713 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -import aria.apache.commons.net.ftp.parser.ConfigurableFTPFileEntryParserImpl; -import aria.apache.commons.net.ftp.parser.FTPTimestampParserImpl; -import java.text.DateFormatSymbols; -import java.util.Collection; -import java.util.Locale; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.TreeMap; - -/** - *

- * This class implements an alternate means of configuring the - * {@link FTPClient FTPClient} object and - * also subordinate objects which it uses. Any class implementing the - * {@link Configurable Configurable } - * interface can be configured by this object. - *

- * In particular this class was designed primarily to support configuration - * of FTP servers which express file timestamps in formats and languages - * other than those for the US locale, which although it is the most common - * is not universal. Unfortunately, nothing in the FTP spec allows this to - * be determined in an automated way, so manual configuration such as this - * is necessary. - *

- * This functionality was designed to allow existing clients to work exactly - * as before without requiring use of this component. This component should - * only need to be explicitly invoked by the user of this package for problem - * cases that previous implementations could not solve. - *

- *

Examples of use of FTPClientConfig

- * Use cases: - * You are trying to access a server that - *
    - *
  • lists files with timestamps that use month names in languages other - * than English
  • - *
  • lists files with timestamps that use date formats other - * than the American English "standard" MM dd yyyy
  • - *
  • is in different timezone and you need accurate timestamps for - * dependency checking as in Ant
  • - *
- *

- * Unpaged (whole list) access on a UNIX server that uses French month names - * but uses the "standard" MMM d yyyy date formatting - *

- *    FTPClient f=FTPClient();
- *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
- *    conf.setServerLanguageCode("fr");
- *    f.configure(conf);
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = listFiles(directory);
- * 
- *

- * Paged access on a UNIX server that uses Danish month names - * and "European" date formatting in Denmark's time zone, when you - * are in some other time zone. - *

- *    FTPClient f=FTPClient();
- *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
- *    conf.setServerLanguageCode("da");
- *    conf.setDefaultDateFormat("d MMM yyyy");
- *    conf.setRecentDateFormat("d MMM HH:mm");
- *    conf.setTimeZoneId("Europe/Copenhagen");
- *    f.configure(conf);
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPListParseEngine engine =
- *       f.initiateListParsing("com.whatever.YourOwnParser", directory);
- *
- *    while (engine.hasNext()) {
- *       FTPFile[] files = engine.getNext(25);  // "page size" you want
- *       //do whatever you want with these files, display them, etc.
- *       //expensive FTPFile objects not created until needed.
- *    }
- * 
- *

- * Unpaged (whole list) access on a VMS server that uses month names - * in a language not {@link #getSupportedLanguageCodes() supported} by the system. - * but uses the "standard" MMM d yyyy date formatting - *

- *    FTPClient f=FTPClient();
- *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_VMS);
- *    conf.setShortMonthNames(
- *        "jan|feb|mar|apr|ma\u00ED|j\u00FAn|j\u00FAl|\u00e1g\u00FA|sep|okt|n\u00F3v|des");
- *    f.configure(conf);
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = listFiles(directory);
- * 
- *

- * Unpaged (whole list) access on a Windows-NT server in a different time zone. - * (Note, since the NT Format uses numeric date formatting, language issues - * are irrelevant here). - *

- *    FTPClient f=FTPClient();
- *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
- *    conf.setTimeZoneId("America/Denver");
- *    f.configure(conf);
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = listFiles(directory);
- * 
- * Unpaged (whole list) access on a Windows-NT server in a different time zone - * but which has been configured to use a unix-style listing format. - *
- *    FTPClient f=FTPClient();
- *    FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_UNIX);
- *    conf.setTimeZoneId("America/Denver");
- *    f.configure(conf);
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = listFiles(directory);
- * 
- * - * @see Configurable - * @see FTPClient - * @see FTPTimestampParserImpl#configure(FTPClientConfig) - * @see ConfigurableFTPFileEntryParserImpl - * @since 1.4 - */ -public class FTPClientConfig { - - /** - * Identifier by which a unix-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_UNIX = "UNIX"; - - /** - * Identifier for alternate UNIX parser; same as {@link #SYST_UNIX} but leading spaces are - * trimmed from file names. This is to maintain backwards compatibility with - * the original behaviour of the parser which ignored multiple spaces between the date - * and the start of the file name. - * - * @since 3.4 - */ - public static final String SYST_UNIX_TRIM_LEADING = "UNIX_LTRIM"; - - /** - * Identifier by which a vms-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_VMS = "VMS"; - - /** - * Identifier by which a WindowsNT-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_NT = "WINDOWS"; - - /** - * Identifier by which an OS/2-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_OS2 = "OS/2"; - - /** - * Identifier by which an OS/400-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_OS400 = "OS/400"; - - /** - * Identifier by which an AS/400-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_AS400 = "AS/400"; - - /** - * Identifier by which an MVS-based ftp server is known throughout - * the commons-net ftp system. - */ - public static final String SYST_MVS = "MVS"; - - /** - * Some servers return an "UNKNOWN Type: L8" message - * in response to the SYST command. We set these to be a Unix-type system. - * This may happen if the ftpd in question was compiled without system - * information. - * - * NET-230 - Updated to be UPPERCASE so that the check done in - * createFileEntryParser will succeed. - * - * @since 1.5 - */ - public static final String SYST_L8 = "TYPE: L8"; - - /** - * Identifier by which an Netware-based ftp server is known throughout - * the commons-net ftp system. - * - * @since 1.5 - */ - public static final String SYST_NETWARE = "NETWARE"; - - /** - * Identifier by which a Mac pre OS-X -based ftp server is known throughout - * the commons-net ftp system. - * - * @since 3.1 - */ - // Full string is "MACOS Peter's Server"; the substring below should be enough - public static final String SYST_MACOS_PETER = "MACOS PETER"; // NET-436 - - private final String serverSystemKey; - private String defaultDateFormatStr = null; - private String recentDateFormatStr = null; - private boolean lenientFutureDates = true; // NET-407 - private String serverLanguageCode = null; - private String shortMonthNames = null; - private String serverTimeZoneId = null; - private boolean saveUnparseableEntries = false; - - /** - * The main constructor for an FTPClientConfig object - * - * @param systemKey key representing system type of the server being - * connected to. See {@link #getServerSystemKey() serverSystemKey} - * If set to the empty string, then FTPClient uses the system type returned by the server. - * However this is not recommended for general use; - * the correct system type should be set if it is known. - */ - public FTPClientConfig(String systemKey) { - this.serverSystemKey = systemKey; - } - - /** - * Convenience constructor mainly for use in testing. - * Constructs a UNIX configuration. - */ - public FTPClientConfig() { - this(SYST_UNIX); - } - - /** - * Constructor which allows setting of the format string member fields - * - * @param systemKey key representing system type of the server being - * connected to. See - * {@link #getServerSystemKey() serverSystemKey} - * @param defaultDateFormatStr See - * {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} - * @param recentDateFormatStr See - * {@link #setRecentDateFormatStr(String) recentDateFormatStr} - * @since 3.6 - */ - public FTPClientConfig(String systemKey, String defaultDateFormatStr, - String recentDateFormatStr) { - this(systemKey); - this.defaultDateFormatStr = defaultDateFormatStr; - this.recentDateFormatStr = recentDateFormatStr; - } - - /** - * Constructor which allows setting of most member fields - * - * @param systemKey key representing system type of the server being - * connected to. See - * {@link #getServerSystemKey() serverSystemKey} - * @param defaultDateFormatStr See - * {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} - * @param recentDateFormatStr See - * {@link #setRecentDateFormatStr(String) recentDateFormatStr} - * @param serverLanguageCode See - * {@link #setServerLanguageCode(String) serverLanguageCode} - * @param shortMonthNames See - * {@link #setShortMonthNames(String) shortMonthNames} - * @param serverTimeZoneId See - * {@link #setServerTimeZoneId(String) serverTimeZoneId} - */ - public FTPClientConfig(String systemKey, String defaultDateFormatStr, String recentDateFormatStr, - String serverLanguageCode, String shortMonthNames, String serverTimeZoneId) { - this(systemKey); - this.defaultDateFormatStr = defaultDateFormatStr; - this.recentDateFormatStr = recentDateFormatStr; - this.serverLanguageCode = serverLanguageCode; - this.shortMonthNames = shortMonthNames; - this.serverTimeZoneId = serverTimeZoneId; - } - - /** - * Constructor which allows setting of all member fields - * - * @param systemKey key representing system type of the server being - * connected to. See - * {@link #getServerSystemKey() serverSystemKey} - * @param defaultDateFormatStr See - * {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} - * @param recentDateFormatStr See - * {@link #setRecentDateFormatStr(String) recentDateFormatStr} - * @param serverLanguageCode See - * {@link #setServerLanguageCode(String) serverLanguageCode} - * @param shortMonthNames See - * {@link #setShortMonthNames(String) shortMonthNames} - * @param serverTimeZoneId See - * {@link #setServerTimeZoneId(String) serverTimeZoneId} - * @param lenientFutureDates See - * {@link #setLenientFutureDates(boolean) lenientFutureDates} - * @param saveUnparseableEntries See - * {@link #setUnparseableEntries(boolean) saveUnparseableEntries} - */ - public FTPClientConfig(String systemKey, String defaultDateFormatStr, String recentDateFormatStr, - String serverLanguageCode, String shortMonthNames, String serverTimeZoneId, - boolean lenientFutureDates, boolean saveUnparseableEntries) { - this(systemKey); - this.defaultDateFormatStr = defaultDateFormatStr; - this.lenientFutureDates = lenientFutureDates; - this.recentDateFormatStr = recentDateFormatStr; - this.saveUnparseableEntries = saveUnparseableEntries; - this.serverLanguageCode = serverLanguageCode; - this.shortMonthNames = shortMonthNames; - this.serverTimeZoneId = serverTimeZoneId; - } - - // Copy constructor, intended for use by FTPClient only - FTPClientConfig(String systemKey, FTPClientConfig config) { - this.serverSystemKey = systemKey; - this.defaultDateFormatStr = config.defaultDateFormatStr; - this.lenientFutureDates = config.lenientFutureDates; - this.recentDateFormatStr = config.recentDateFormatStr; - this.saveUnparseableEntries = config.saveUnparseableEntries; - this.serverLanguageCode = config.serverLanguageCode; - this.serverTimeZoneId = config.serverTimeZoneId; - this.shortMonthNames = config.shortMonthNames; - } - - /** - * Copy constructor - * - * @param config source - * @since 3.6 - */ - public FTPClientConfig(FTPClientConfig config) { - this.serverSystemKey = config.serverSystemKey; - this.defaultDateFormatStr = config.defaultDateFormatStr; - this.lenientFutureDates = config.lenientFutureDates; - this.recentDateFormatStr = config.recentDateFormatStr; - this.saveUnparseableEntries = config.saveUnparseableEntries; - this.serverLanguageCode = config.serverLanguageCode; - this.serverTimeZoneId = config.serverTimeZoneId; - this.shortMonthNames = config.shortMonthNames; - } - - private static final Map LANGUAGE_CODE_MAP = new TreeMap(); - - static { - - // if there are other commonly used month name encodings which - // correspond to particular locales, please add them here. - - // many locales code short names for months as all three letters - // these we handle simply. - LANGUAGE_CODE_MAP.put("en", Locale.ENGLISH); - LANGUAGE_CODE_MAP.put("de", Locale.GERMAN); - LANGUAGE_CODE_MAP.put("it", Locale.ITALIAN); - LANGUAGE_CODE_MAP.put("es", new Locale("es", "", "")); // spanish - LANGUAGE_CODE_MAP.put("pt", new Locale("pt", "", "")); // portuguese - LANGUAGE_CODE_MAP.put("da", new Locale("da", "", "")); // danish - LANGUAGE_CODE_MAP.put("sv", new Locale("sv", "", "")); // swedish - LANGUAGE_CODE_MAP.put("no", new Locale("no", "", "")); // norwegian - LANGUAGE_CODE_MAP.put("nl", new Locale("nl", "", "")); // dutch - LANGUAGE_CODE_MAP.put("ro", new Locale("ro", "", "")); // romanian - LANGUAGE_CODE_MAP.put("sq", new Locale("sq", "", "")); // albanian - LANGUAGE_CODE_MAP.put("sh", new Locale("sh", "", "")); // serbo-croatian - LANGUAGE_CODE_MAP.put("sk", new Locale("sk", "", "")); // slovak - LANGUAGE_CODE_MAP.put("sl", new Locale("sl", "", "")); // slovenian - - // some don't - LANGUAGE_CODE_MAP.put("fr", - "jan|f\u00e9v|mar|avr|mai|jun|jui|ao\u00fb|sep|oct|nov|d\u00e9c"); //french - } - - /** - * Getter for the serverSystemKey property. This property - * specifies the general type of server to which the client connects. - * Should be either one of the FTPClientConfig.SYST_* codes - * or else the fully qualified class name of a parser implementing both - * the FTPFileEntryParser and Configurable - * interfaces. - * - * @return Returns the serverSystemKey property. - */ - public String getServerSystemKey() { - return serverSystemKey; - } - - /** - * getter for the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} - * property. - * - * @return Returns the defaultDateFormatStr property. - */ - public String getDefaultDateFormatStr() { - return defaultDateFormatStr; - } - - /** - * getter for the {@link #setRecentDateFormatStr(String) recentDateFormatStr} property. - * - * @return Returns the recentDateFormatStr property. - */ - - public String getRecentDateFormatStr() { - return recentDateFormatStr; - } - - /** - * getter for the {@link #setServerTimeZoneId(String) serverTimeZoneId} property. - * - * @return Returns the serverTimeZoneId property. - */ - public String getServerTimeZoneId() { - return serverTimeZoneId; - } - - /** - *

- * getter for the {@link #setShortMonthNames(String) shortMonthNames} - * property. - *

- * - * @return Returns the shortMonthNames. - */ - public String getShortMonthNames() { - return shortMonthNames; - } - - /** - *

- * getter for the {@link #setServerLanguageCode(String) serverLanguageCode} property. - *

- * - * @return Returns the serverLanguageCode property. - */ - public String getServerLanguageCode() { - return serverLanguageCode; - } - - /** - *

- * getter for the {@link #setLenientFutureDates(boolean) lenientFutureDates} property. - *

- * - * @return Returns the lenientFutureDates. - * @since 1.5 - */ - public boolean isLenientFutureDates() { - return lenientFutureDates; - } - - /** - *

- * setter for the defaultDateFormatStr property. This property - * specifies the main date format that will be used by a parser configured - * by this configuration to parse file timestamps. If this is not - * specified, such a parser will use as a default value, the most commonly - * used format which will be in as used in en_US locales. - *

- * This should be in the format described for - * java.text.SimpleDateFormat. - * property. - *

- * - * @param defaultDateFormatStr The defaultDateFormatStr to set. - */ - public void setDefaultDateFormatStr(String defaultDateFormatStr) { - this.defaultDateFormatStr = defaultDateFormatStr; - } - - /** - *

- * setter for the recentDateFormatStr property. This property - * specifies a secondary date format that will be used by a parser - * configured by this configuration to parse file timestamps, typically - * those less than a year old. If this is not specified, such a parser - * will not attempt to parse using an alternate format. - *

- *

- * This is used primarily in unix-based systems. - *

- *

- * This should be in the format described for - * java.text.SimpleDateFormat. - *

- * - * @param recentDateFormatStr The recentDateFormatStr to set. - */ - public void setRecentDateFormatStr(String recentDateFormatStr) { - this.recentDateFormatStr = recentDateFormatStr; - } - - /** - *

- * setter for the lenientFutureDates property. This boolean property - * (default: false) only has meaning when a - * {@link #setRecentDateFormatStr(String) recentDateFormatStr} property - * has been set. In that case, if this property is set true, then the - * parser, when it encounters a listing parseable with the recent date - * format, will only consider a date to belong to the previous year if - * it is more than one day in the future. This will allow all - * out-of-synch situations (whether based on "slop" - i.e. servers simply - * out of synch with one another or because of time zone differences - - * but in the latter case it is highly recommended to use the - * {@link #setServerTimeZoneId(String) serverTimeZoneId} property - * instead) to resolve correctly. - *

- * This is used primarily in unix-based systems. - *

- * - * @param lenientFutureDates set true to compensate for out-of-synch - * conditions. - */ - public void setLenientFutureDates(boolean lenientFutureDates) { - this.lenientFutureDates = lenientFutureDates; - } - - /** - *

- * setter for the serverTimeZoneId property. This property - * allows a time zone to be specified corresponding to that known to be - * used by an FTP server in file listings. This might be particularly - * useful to clients such as Ant that try to use these timestamps for - * dependency checking. - *

- * This should be one of the identifiers used by - * java.util.TimeZone to refer to time zones, for example, - * America/Chicago or Asia/Rangoon. - *

- * - * @param serverTimeZoneId The serverTimeZoneId to set. - */ - public void setServerTimeZoneId(String serverTimeZoneId) { - this.serverTimeZoneId = serverTimeZoneId; - } - - /** - *

- * setter for the shortMonthNames property. - * This property allows the user to specify a set of month names - * used by the server that is different from those that may be - * specified using the {@link #setServerLanguageCode(String) serverLanguageCode} - * property. - *

- * This should be a string containing twelve strings each composed of - * three characters, delimited by pipe (|) characters. Currently, - * only 8-bit ASCII characters are known to be supported. For example, - * a set of month names used by a hypothetical Icelandic FTP server might - * conceivably be specified as - * "jan|feb|mar|apr|maí|jún|júl|ágú|sep|okt|nóv|des". - *

- * - * @param shortMonthNames The value to set to the shortMonthNames property. - */ - public void setShortMonthNames(String shortMonthNames) { - this.shortMonthNames = shortMonthNames; - } - - /** - *

- * setter for the serverLanguageCode property. This property allows - * user to specify a - * - * two-letter ISO-639 language code that will be used to - * configure the set of month names used by the file timestamp parser. - * If neither this nor the {@link #setShortMonthNames(String) shortMonthNames} - * is specified, parsing will assume English month names, which may or - * may not be significant, depending on whether the date format(s) - * specified via {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} - * and/or {@link #setRecentDateFormatStr(String) recentDateFormatStr} are using - * numeric or alphabetic month names. - *

- *

If the code supplied is not supported here, en_US - * month names will be used. We are supporting here those language - * codes which, when a java.util.Locale is constucted - * using it, and a java.text.SimpleDateFormat is - * constructed using that Locale, the array returned by the - * SimpleDateFormat's getShortMonths() method consists - * solely of three 8-bit ASCII character strings. Additionally, - * languages which do not meet this requirement are included if a - * common alternative set of short month names is known to be used. - * This means that users who can tell us of additional such encodings - * may get them added to the list of supported languages by contacting - * the Apache Commons Net team. - *

- *

- * Please note that this attribute will NOT be used to determine a - * locale-based date format for the language. - * Experience has shown that many if not most FTP servers outside the - * United States employ the standard en_US date format - * orderings of MMM d yyyy and MMM d HH:mm - * and attempting to deduce this automatically here would cause more - * problems than it would solve. The date format must be changed - * via the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} and/or - * {@link #setRecentDateFormatStr(String) recentDateFormatStr} parameters. - *

- * - * @param serverLanguageCode The value to set to the serverLanguageCode property. - */ - public void setServerLanguageCode(String serverLanguageCode) { - this.serverLanguageCode = serverLanguageCode; - } - - /** - * Looks up the supplied language code in the internally maintained table of - * language codes. Returns a DateFormatSymbols object configured with - * short month names corresponding to the code. If there is no corresponding - * entry in the table, the object returned will be that for - * Locale.US - * - * @param languageCode See {@link #setServerLanguageCode(String) serverLanguageCode} - * @return a DateFormatSymbols object configured with short month names - * corresponding to the supplied code, or with month names for - * Locale.US if there is no corresponding entry in the internal - * table. - */ - public static DateFormatSymbols lookupDateFormatSymbols(String languageCode) { - Object lang = LANGUAGE_CODE_MAP.get(languageCode); - if (lang != null) { - if (lang instanceof Locale) { - return new DateFormatSymbols((Locale) lang); - } else if (lang instanceof String) { - return getDateFormatSymbols((String) lang); - } - } - return new DateFormatSymbols(Locale.US); - } - - /** - * Returns a DateFormatSymbols object configured with short month names - * as in the supplied string - * - * @param shortmonths This should be as described in - * {@link #setShortMonthNames(String) shortMonthNames} - * @return a DateFormatSymbols object configured with short month names - * as in the supplied string - */ - public static DateFormatSymbols getDateFormatSymbols(String shortmonths) { - String[] months = splitShortMonthString(shortmonths); - DateFormatSymbols dfs = new DateFormatSymbols(Locale.US); - dfs.setShortMonths(months); - return dfs; - } - - private static String[] splitShortMonthString(String shortmonths) { - StringTokenizer st = new StringTokenizer(shortmonths, "|"); - int monthcnt = st.countTokens(); - if (12 != monthcnt) { - throw new IllegalArgumentException("expecting a pipe-delimited string containing 12 tokens"); - } - String[] months = new String[13]; - int pos = 0; - while (st.hasMoreTokens()) { - months[pos++] = st.nextToken(); - } - months[pos] = ""; - return months; - } - - /** - * Returns a Collection of all the language codes currently supported - * by this class. See {@link #setServerLanguageCode(String) serverLanguageCode} - * for a functional descrption of language codes within this system. - * - * @return a Collection of all the language codes currently supported - * by this class - */ - public static Collection getSupportedLanguageCodes() { - return LANGUAGE_CODE_MAP.keySet(); - } - - /** - * Allow list parsing methods to create basic FTPFile entries if parsing fails. - *

- * In this case, the FTPFile will contain only the unparsed entry {@link FTPFile#getRawListing()} - * and {@link FTPFile#isValid()} will return {@code false} - * - * @param saveUnparseable if true, then create FTPFile entries if parsing fails - * @since 3.4 - */ - public void setUnparseableEntries(boolean saveUnparseable) { - this.saveUnparseableEntries = saveUnparseable; - } - - /** - * @return true if list parsing should return FTPFile entries even for unparseable response lines - *

- * If true, the FTPFile for any unparseable entries will contain only the unparsed entry - * {@link FTPFile#getRawListing()} and {@link FTPFile#isValid()} will return {@code false} - * @since 3.4 - */ - public boolean getUnparseableEntries() { - return this.saveUnparseableEntries; - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPCmd.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPCmd.java deleted file mode 100644 index de14835b..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPCmd.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -/** - * @since 3.3 - */ -public enum FTPCmd { - ABOR, ACCT, ALLO, APPE, CDUP, CWD, DELE, EPRT, EPSV, FEAT, HELP, LIST, MDTM, MFMT, MKD, MLSD, MLST, MODE, NLST, NOOP, PASS, PASV, PORT, PWD, QUIT, REIN, REST, RETR, RMD, RNFR, RNTO, SITE, SMNT, STAT, STOR, STOU, STRU, SYST, TYPE, USER,; - - // Aliases - - public static final FTPCmd ABORT = ABOR; - public static final FTPCmd ACCOUNT = ACCT; - public static final FTPCmd ALLOCATE = ALLO; - public static final FTPCmd APPEND = APPE; - public static final FTPCmd CHANGE_TO_PARENT_DIRECTORY = CDUP; - public static final FTPCmd CHANGE_WORKING_DIRECTORY = CWD; - public static final FTPCmd DATA_PORT = PORT; - public static final FTPCmd DELETE = DELE; - public static final FTPCmd FEATURES = FEAT; - public static final FTPCmd FILE_STRUCTURE = STRU; - public static final FTPCmd GET_MOD_TIME = MDTM; - public static final FTPCmd LOGOUT = QUIT; - public static final FTPCmd MAKE_DIRECTORY = MKD; - public static final FTPCmd MOD_TIME = MDTM; - public static final FTPCmd NAME_LIST = NLST; - public static final FTPCmd PASSIVE = PASV; - public static final FTPCmd PASSWORD = PASS; - public static final FTPCmd PRINT_WORKING_DIRECTORY = PWD; - public static final FTPCmd REINITIALIZE = REIN; - public static final FTPCmd REMOVE_DIRECTORY = RMD; - public static final FTPCmd RENAME_FROM = RNFR; - public static final FTPCmd RENAME_TO = RNTO; - public static final FTPCmd REPRESENTATION_TYPE = TYPE; - public static final FTPCmd RESTART = REST; - public static final FTPCmd RETRIEVE = RETR; - public static final FTPCmd SET_MOD_TIME = MFMT; - public static final FTPCmd SITE_PARAMETERS = SITE; - public static final FTPCmd STATUS = STAT; - public static final FTPCmd STORE = STOR; - public static final FTPCmd STORE_UNIQUE = STOU; - public static final FTPCmd STRUCTURE_MOUNT = SMNT; - public static final FTPCmd SYSTEM = SYST; - public static final FTPCmd TRANSFER_MODE = MODE; - public static final FTPCmd USERNAME = USER; - - /** - * Retrieve the FTP protocol command string corresponding to a specified - * command code. - * - * @return The FTP protcol command string corresponding to a specified - * command code. - */ - public final String getCommand() { - return this.name(); - } - -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPCommand.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPCommand.java deleted file mode 100644 index 3a1aef89..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPCommand.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -/** - * FTPCommand stores a set of constants for FTP command codes. To interpret - * the meaning of the codes, familiarity with RFC 959 is assumed. - * The mnemonic constant names are transcriptions from the code descriptions - * of RFC 959. For those who think in terms of the actual FTP commands, - * a set of constants such as {@link #USER USER } are provided - * where the constant name is the same as the FTP command. - * - * @deprecated use {@link FTPCmd} instead - */ -@Deprecated public final class FTPCommand { - - public static final int USER = 0; - public static final int PASS = 1; - public static final int ACCT = 2; - public static final int CWD = 3; - public static final int CDUP = 4; - public static final int SMNT = 5; - public static final int REIN = 6; - public static final int QUIT = 7; - public static final int PORT = 8; - public static final int PASV = 9; - public static final int TYPE = 10; - public static final int STRU = 11; - public static final int MODE = 12; - public static final int RETR = 13; - public static final int STOR = 14; - public static final int STOU = 15; - public static final int APPE = 16; - public static final int ALLO = 17; - public static final int REST = 18; - public static final int RNFR = 19; - public static final int RNTO = 20; - public static final int ABOR = 21; - public static final int DELE = 22; - public static final int RMD = 23; - public static final int MKD = 24; - public static final int PWD = 25; - public static final int LIST = 26; - public static final int NLST = 27; - public static final int SITE = 28; - public static final int SYST = 29; - public static final int STAT = 30; - public static final int HELP = 31; - public static final int NOOP = 32; - /** @since 2.0 */ - public static final int MDTM = 33; - /** @since 2.2 */ - public static final int FEAT = 34; - /** @since 2.2 */ - public static final int MFMT = 35; - /** @since 2.2 */ - public static final int EPSV = 36; - /** @since 2.2 */ - public static final int EPRT = 37; - - /** - * Machine parseable list for a directory - * - * @since 3.0 - */ - public static final int MLSD = 38; - - /** - * Machine parseable list for a single file - * - * @since 3.0 - */ - public static final int MLST = 39; - - // Must agree with final entry above; used to check array size - private static final int LAST = MLST; - - public static final int USERNAME = USER; - public static final int PASSWORD = PASS; - public static final int ACCOUNT = ACCT; - public static final int CHANGE_WORKING_DIRECTORY = CWD; - public static final int CHANGE_TO_PARENT_DIRECTORY = CDUP; - public static final int STRUCTURE_MOUNT = SMNT; - public static final int REINITIALIZE = REIN; - public static final int LOGOUT = QUIT; - public static final int DATA_PORT = PORT; - public static final int PASSIVE = PASV; - public static final int REPRESENTATION_TYPE = TYPE; - public static final int FILE_STRUCTURE = STRU; - public static final int TRANSFER_MODE = MODE; - public static final int RETRIEVE = RETR; - public static final int STORE = STOR; - public static final int STORE_UNIQUE = STOU; - public static final int APPEND = APPE; - public static final int ALLOCATE = ALLO; - public static final int RESTART = REST; - public static final int RENAME_FROM = RNFR; - public static final int RENAME_TO = RNTO; - public static final int ABORT = ABOR; - public static final int DELETE = DELE; - public static final int REMOVE_DIRECTORY = RMD; - public static final int MAKE_DIRECTORY = MKD; - public static final int PRINT_WORKING_DIRECTORY = PWD; - // public static final int LIST = LIST; - public static final int NAME_LIST = NLST; - public static final int SITE_PARAMETERS = SITE; - public static final int SYSTEM = SYST; - public static final int STATUS = STAT; - //public static final int HELP = HELP; - //public static final int NOOP = NOOP; - - /** @since 2.0 */ - public static final int MOD_TIME = MDTM; - - /** @since 2.2 */ - public static final int FEATURES = FEAT; - /** @since 2.2 */ - public static final int GET_MOD_TIME = MDTM; - /** @since 2.2 */ - public static final int SET_MOD_TIME = MFMT; - - // Cannot be instantiated - private FTPCommand() { - } - - private static final String[] _commands = { - "USER", "PASS", "ACCT", "CWD", "CDUP", "SMNT", "REIN", "QUIT", "PORT", "PASV", "TYPE", "STRU", - "MODE", "RETR", "STOR", "STOU", "APPE", "ALLO", "REST", "RNFR", "RNTO", "ABOR", "DELE", "RMD", - "MKD", "PWD", "LIST", "NLST", "SITE", "SYST", "STAT", "HELP", "NOOP", "MDTM", "FEAT", "MFMT", - "EPSV", "EPRT", "MLSD", "MLST" - }; - - // default access needed for Unit test - static void checkArray() { - int expectedLength = LAST + 1; - if (_commands.length != expectedLength) { - throw new RuntimeException("Incorrect _commands array. Should have length " - + expectedLength - + " found " - + _commands.length); - } - } - - /** - * Retrieve the FTP protocol command string corresponding to a specified - * command code. - * - * @param command The command code. - * @return The FTP protcol command string corresponding to a specified - * command code. - */ - public static final String getCommand(int command) { - return _commands[command]; - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPConnectionClosedException.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPConnectionClosedException.java deleted file mode 100644 index aa95277e..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPConnectionClosedException.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -import java.io.IOException; - -/*** - * FTPConnectionClosedException is used to indicate the premature or - * unexpected closing of an FTP connection resulting from a - * {@link FTPReply#SERVICE_NOT_AVAILABLE FTPReply.SERVICE_NOT_AVAILABLE } - * response (FTP reply code 421) to a - * failed FTP command. This exception is derived from IOException and - * therefore may be caught either as an IOException or specifically as an - * FTPConnectionClosedException. - * - * @see FTP - * @see FTPClient - ***/ - -public class FTPConnectionClosedException extends IOException { - - private static final long serialVersionUID = 3500547241659379952L; - - /*** Constructs a FTPConnectionClosedException with no message ***/ - public FTPConnectionClosedException() { - super(); - } - - /*** - * Constructs a FTPConnectionClosedException with a specified message. - * - * @param message The message explaining the reason for the exception. - ***/ - public FTPConnectionClosedException(String message) { - super(message); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPFile.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPFile.java deleted file mode 100644 index 5edcc119..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPFile.java +++ /dev/null @@ -1,493 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -import java.io.Serializable; -import java.util.Calendar; -import java.util.Date; -import java.util.Formatter; -import java.util.TimeZone; - -/*** - * The FTPFile class is used to represent information about files stored - * on an FTP server. - * - * @see FTPFileEntryParser - * @see FTPClient#listFiles - ***/ - -public class FTPFile implements Serializable { - private static final long serialVersionUID = 9010790363003271996L; - - /** A constant indicating an FTPFile is a file. ***/ - public static final int FILE_TYPE = 0; - /** A constant indicating an FTPFile is a directory. ***/ - public static final int DIRECTORY_TYPE = 1; - /** A constant indicating an FTPFile is a symbolic link. ***/ - public static final int SYMBOLIC_LINK_TYPE = 2; - /** A constant indicating an FTPFile is of unknown type. ***/ - public static final int UNKNOWN_TYPE = 3; - - /** A constant indicating user access permissions. ***/ - public static final int USER_ACCESS = 0; - /** A constant indicating group access permissions. ***/ - public static final int GROUP_ACCESS = 1; - /** A constant indicating world access permissions. ***/ - public static final int WORLD_ACCESS = 2; - - /** A constant indicating file/directory read permission. ***/ - public static final int READ_PERMISSION = 0; - /** A constant indicating file/directory write permission. ***/ - public static final int WRITE_PERMISSION = 1; - /** - * A constant indicating file execute permission or directory listing - * permission. - ***/ - public static final int EXECUTE_PERMISSION = 2; - - private int _type, _hardLinkCount; - private long _size; - private String _rawListing, _user, _group, _name, _link; - private Calendar _date; - // If this is null, then list entry parsing failed - private final boolean[] _permissions[]; // e.g. _permissions[USER_ACCESS][READ_PERMISSION] - - /*** Creates an empty FTPFile. ***/ - public FTPFile() { - _permissions = new boolean[3][3]; - _type = UNKNOWN_TYPE; - // init these to values that do not occur in listings - // so can distinguish which fields are unset - _hardLinkCount = 0; // 0 is invalid as a link count - _size = -1; // 0 is valid, so use -1 - _user = ""; - _group = ""; - _date = null; - _name = null; - } - - /** - * Constructor for use by {@link FTPListParseEngine} only. - * Used to create FTPFile entries for failed parses - * - * @param rawListing line that could not be parsed. - * @since 3.4 - */ - FTPFile(String rawListing) { - _permissions = null; // flag that entry is invalid - _rawListing = rawListing; - _type = UNKNOWN_TYPE; - // init these to values that do not occur in listings - // so can distinguish which fields are unset - _hardLinkCount = 0; // 0 is invalid as a link count - _size = -1; // 0 is valid, so use -1 - _user = ""; - _group = ""; - _date = null; - _name = null; - } - - /*** - * Set the original FTP server raw listing from which the FTPFile was - * created. - * - * @param rawListing The raw FTP server listing. - ***/ - public void setRawListing(String rawListing) { - _rawListing = rawListing; - } - - /*** - * Get the original FTP server raw listing used to initialize the FTPFile. - * - * @return The original FTP server raw listing used to initialize the - * FTPFile. - ***/ - public String getRawListing() { - return _rawListing; - } - - /*** - * Determine if the file is a directory. - * - * @return True if the file is of type DIRECTORY_TYPE, false if - * not. - ***/ - public boolean isDirectory() { - return (_type == DIRECTORY_TYPE); - } - - /*** - * Determine if the file is a regular file. - * - * @return True if the file is of type FILE_TYPE, false if - * not. - ***/ - public boolean isFile() { - return (_type == FILE_TYPE); - } - - /*** - * Determine if the file is a symbolic link. - * - * @return True if the file is of type UNKNOWN_TYPE, false if - * not. - ***/ - public boolean isSymbolicLink() { - return (_type == SYMBOLIC_LINK_TYPE); - } - - /*** - * Determine if the type of the file is unknown. - * - * @return True if the file is of type UNKNOWN_TYPE, false if - * not. - ***/ - public boolean isUnknown() { - return (_type == UNKNOWN_TYPE); - } - - /** - * Used to indicate whether an entry is valid or not. - * If the entry is invalid, only the {@link #getRawListing()} method will be useful. - * Other methods may fail. - * - * Used in conjunction with list parsing that preseverves entries that failed to parse. - * - * @return true if the entry is valid - * @see FTPClientConfig#setUnparseableEntries(boolean) - * @since 3.4 - */ - public boolean isValid() { - return (_permissions != null); - } - - /*** - * Set the type of the file (DIRECTORY_TYPE, - * FILE_TYPE, etc.). - * - * @param type The integer code representing the type of the file. - ***/ - public void setType(int type) { - _type = type; - } - - /*** - * Return the type of the file (one of the _TYPE constants), - * e.g., if it is a directory, a regular file, or a symbolic link. - * - * @return The type of the file. - ***/ - public int getType() { - return _type; - } - - /*** - * Set the name of the file. - * - * @param name The name of the file. - ***/ - public void setName(String name) { - _name = name; - } - - /*** - * Return the name of the file. - * - * @return The name of the file. - ***/ - public String getName() { - return _name; - } - - /** - * Set the file size in bytes. - * - * @param size The file size in bytes. - */ - public void setSize(long size) { - _size = size; - } - - /*** - * Return the file size in bytes. - * - * @return The file size in bytes. - ***/ - public long getSize() { - return _size; - } - - /*** - * Set the number of hard links to this file. This is not to be - * confused with symbolic links. - * - * @param links The number of hard links to this file. - ***/ - public void setHardLinkCount(int links) { - _hardLinkCount = links; - } - - /*** - * Return the number of hard links to this file. This is not to be - * confused with symbolic links. - * - * @return The number of hard links to this file. - ***/ - public int getHardLinkCount() { - return _hardLinkCount; - } - - /*** - * Set the name of the group owning the file. This may be - * a string representation of the group number. - * - * @param group The name of the group owning the file. - ***/ - public void setGroup(String group) { - _group = group; - } - - /*** - * Returns the name of the group owning the file. Sometimes this will be - * a string representation of the group number. - * - * @return The name of the group owning the file. - ***/ - public String getGroup() { - return _group; - } - - /*** - * Set the name of the user owning the file. This may be - * a string representation of the user number; - * - * @param user The name of the user owning the file. - ***/ - public void setUser(String user) { - _user = user; - } - - /*** - * Returns the name of the user owning the file. Sometimes this will be - * a string representation of the user number. - * - * @return The name of the user owning the file. - ***/ - public String getUser() { - return _user; - } - - /*** - * If the FTPFile is a symbolic link, use this method to set the name of the - * file being pointed to by the symbolic link. - * - * @param link The file pointed to by the symbolic link. - ***/ - public void setLink(String link) { - _link = link; - } - - /*** - * If the FTPFile is a symbolic link, this method returns the name of the - * file being pointed to by the symbolic link. Otherwise it returns null. - * - * @return The file pointed to by the symbolic link (null if the FTPFile - * is not a symbolic link). - ***/ - public String getLink() { - return _link; - } - - /*** - * Set the file timestamp. This usually the last modification time. - * The parameter is not cloned, so do not alter its value after calling - * this method. - * - * @param date A Calendar instance representing the file timestamp. - ***/ - public void setTimestamp(Calendar date) { - _date = date; - } - - /*** - * Returns the file timestamp. This usually the last modification time. - * - * @return A Calendar instance representing the file timestamp. - ***/ - public Calendar getTimestamp() { - return _date; - } - - /*** - * Set if the given access group (one of the _ACCESS - * constants) has the given access permission (one of the - * _PERMISSION constants) to the file. - * - * @param access The access group (one of the _ACCESS - * constants) - * @param permission The access permission (one of the - * _PERMISSION constants) - * @param value True if permission is allowed, false if not. - * @throws ArrayIndexOutOfBoundsException if either of the parameters is out of range - ***/ - public void setPermission(int access, int permission, boolean value) { - _permissions[access][permission] = value; - } - - /*** - * Determines if the given access group (one of the _ACCESS - * constants) has the given access permission (one of the - * _PERMISSION constants) to the file. - * - * @param access The access group (one of the _ACCESS - * constants) - * @param permission The access permission (one of the - * _PERMISSION constants) - * @throws ArrayIndexOutOfBoundsException if either of the parameters is out of range - * @return true if {@link #isValid()} is {@code true &&} the associated permission is set; - * {@code false} otherwise. - ***/ - public boolean hasPermission(int access, int permission) { - if (_permissions == null) { - return false; - } - return _permissions[access][permission]; - } - - /*** - * Returns a string representation of the FTPFile information. - * - * @return A string representation of the FTPFile information. - */ - @Override public String toString() { - return getRawListing(); - } - - /*** - * Returns a string representation of the FTPFile information. - * This currently mimics the Unix listing format. - * This method uses the timezone of the Calendar entry, which is - * the server time zone (if one was provided) otherwise it is - * the local time zone. - *

- * Note: if the instance is not valid {@link #isValid()}, no useful - * information can be returned. In this case, use {@link #getRawListing()} - * instead. - * - * @return A string representation of the FTPFile information. - * @since 3.0 - */ - public String toFormattedString() { - return toFormattedString(null); - } - - /** - * Returns a string representation of the FTPFile information. - * This currently mimics the Unix listing format. - * This method allows the Calendar time zone to be overridden. - *

- * Note: if the instance is not valid {@link #isValid()}, no useful - * information can be returned. In this case, use {@link #getRawListing()} - * instead. - * - * @param timezone the timezone to use for displaying the time stamp - * If {@code null}, then use the Calendar entry timezone - * @return A string representation of the FTPFile information. - * @since 3.4 - */ - public String toFormattedString(final String timezone) { - - if (!isValid()) { - return "[Invalid: could not parse file entry]"; - } - StringBuilder sb = new StringBuilder(); - Formatter fmt = new Formatter(sb); - sb.append(formatType()); - sb.append(permissionToString(USER_ACCESS)); - sb.append(permissionToString(GROUP_ACCESS)); - sb.append(permissionToString(WORLD_ACCESS)); - fmt.format(" %4d", Integer.valueOf(getHardLinkCount())); - fmt.format(" %-8s %-8s", getUser(), getGroup()); - fmt.format(" %8d", Long.valueOf(getSize())); - Calendar timestamp = getTimestamp(); - if (timestamp != null) { - if (timezone != null) { - TimeZone newZone = TimeZone.getTimeZone(timezone); - if (!newZone.equals(timestamp.getTimeZone())) { - Date original = timestamp.getTime(); - Calendar newStamp = Calendar.getInstance(newZone); - newStamp.setTime(original); - timestamp = newStamp; - } - } - fmt.format(" %1$tY-%1$tm-%1$td", timestamp); - // Only display time units if they are present - if (timestamp.isSet(Calendar.HOUR_OF_DAY)) { - fmt.format(" %1$tH", timestamp); - if (timestamp.isSet(Calendar.MINUTE)) { - fmt.format(":%1$tM", timestamp); - if (timestamp.isSet(Calendar.SECOND)) { - fmt.format(":%1$tS", timestamp); - if (timestamp.isSet(Calendar.MILLISECOND)) { - fmt.format(".%1$tL", timestamp); - } - } - } - fmt.format(" %1$tZ", timestamp); - } - } - sb.append(' '); - sb.append(getName()); - fmt.close(); - return sb.toString(); - } - - private char formatType() { - switch (_type) { - case FILE_TYPE: - return '-'; - case DIRECTORY_TYPE: - return 'd'; - case SYMBOLIC_LINK_TYPE: - return 'l'; - default: - return '?'; - } - } - - private String permissionToString(int access) { - StringBuilder sb = new StringBuilder(); - if (hasPermission(access, READ_PERMISSION)) { - sb.append('r'); - } else { - sb.append('-'); - } - if (hasPermission(access, WRITE_PERMISSION)) { - sb.append('w'); - } else { - sb.append('-'); - } - if (hasPermission(access, EXECUTE_PERMISSION)) { - sb.append('x'); - } else { - sb.append('-'); - } - return sb.toString(); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPFileEntryParser.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPFileEntryParser.java deleted file mode 100644 index 0c04b265..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPFileEntryParser.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -import java.io.BufferedReader; -import java.io.IOException; -import java.util.List; - -/** - * FTPFileEntryParser defines the interface for parsing a single FTP file - * listing and converting that information into an - * {@link FTPFile} instance. - * Sometimes you will want to parse unusual listing formats, in which - * case you would create your own implementation of FTPFileEntryParser and - * if necessary, subclass FTPFile. - *

- * Here are some examples showing how to use one of the classes that - * implement this interface. - *

- * - * The first example uses the FTPClient.listFiles() - * API to pull the whole list from the subfolder subfolder in - * one call, attempting to automatically detect the parser type. This - * method, without a parserKey parameter, indicates that autodection should - * be used. - * - *

- *    FTPClient f=FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = f.listFiles("subfolder");
- * 
- * - * The second example uses the FTPClient.listFiles() - * API to pull the whole list from the current working directory in one call, - * but specifying by classname the parser to be used. For this particular - * parser class, this approach is necessary since there is no way to - * autodetect this server type. - * - *
- *    FTPClient f=FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = f.listFiles(
- *      "org.apache.commons.net.ftp.parser.EnterpriseUnixFTPFileEntryParser",
- *      ".");
- * 
- * - * The third example uses the FTPClient.listFiles() - * API to pull a single file listing in an arbitrary directory in one call, - * specifying by KEY the parser to be used, in this case, VMS. - * - *
- *    FTPClient f=FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPFile[] files = f.listFiles("VMS", "subfolder/foo.java");
- * 
- * - * For an alternative approach, see the {@link FTPListParseEngine} class - * which provides iterative access. - * - * @version $Id: FTPFileEntryParser.java 1747119 2016-06-07 02:22:24Z ggregory $ - * @see FTPFile - * @see FTPClient#listFiles() - */ -public interface FTPFileEntryParser { - /** - * Parses a line of an FTP server file listing and converts it into a usable - * format in the form of an FTPFile instance. If the - * file listing line doesn't describe a file, null should be - * returned, otherwise a FTPFile instance representing the - * files in the directory is returned. - * - * @param listEntry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - FTPFile parseFTPEntry(String listEntry); - - /** - * Reads the next entry using the supplied BufferedReader object up to - * whatever delemits one entry from the next. Implementors must define - * this for the particular ftp system being parsed. In many but not all - * cases, this can be defined simply by calling BufferedReader.readLine(). - * - * @param reader The BufferedReader object from which entries are to be - * read. - * @return A string representing the next ftp entry or null if none found. - * @throws IOException thrown on any IO Error reading from the reader. - */ - String readNextEntry(BufferedReader reader) throws IOException; - - /** - * This method is a hook for those implementors (such as - * VMSVersioningFTPEntryParser, and possibly others) which need to - * perform some action upon the FTPFileList after it has been created - * from the server stream, but before any clients see the list. - * - * The default implementation can be a no-op. - * - * @param original Original list after it has been created from the server stream - * @return Original list as processed by this method. - */ - List preParse(List original); -} - - -/* Emacs configuration - * Local variables: ** - * mode: java ** - * c-basic-offset: 4 ** - * indent-tabs-mode: nil ** - * End: ** - */ diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPFileEntryParserImpl.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPFileEntryParserImpl.java deleted file mode 100644 index 5af13643..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPFileEntryParserImpl.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -import java.io.BufferedReader; -import java.io.IOException; -import java.util.List; - -/** - * This abstract class implements both the older FTPFileListParser and - * newer FTPFileEntryParser interfaces with default functionality. - * All the classes in the parser subpackage inherit from this. - */ -public abstract class FTPFileEntryParserImpl implements FTPFileEntryParser { - /** - * The constructor for a FTPFileEntryParserImpl object. - */ - public FTPFileEntryParserImpl() { - } - - /** - * Reads the next entry using the supplied BufferedReader object up to - * whatever delimits one entry from the next. This default implementation - * simply calls BufferedReader.readLine(). - * - * @param reader The BufferedReader object from which entries are to be - * read. - * @return A string representing the next ftp entry or null if none found. - * @throws IOException thrown on any IO Error reading from the reader. - */ - @Override public String readNextEntry(BufferedReader reader) throws IOException { - return reader.readLine(); - } - - /** - * This method is a hook for those implementors (such as - * VMSVersioningFTPEntryParser, and possibly others) which need to - * perform some action upon the FTPFileList after it has been created - * from the server stream, but before any clients see the list. - * - * This default implementation does nothing. - * - * @param original Original list after it has been created from the server stream - * @return original unmodified. - */ - @Override public List preParse(List original) { - return original; - } -} - -/* Emacs configuration - * Local variables: ** - * mode: java ** - * c-basic-offset: 4 ** - * indent-tabs-mode: nil ** - * End: ** - */ diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPFileFilter.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPFileFilter.java deleted file mode 100644 index 898ee154..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPFileFilter.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -/** - * Perform filtering on FTPFile entries. - * - * @since 2.2 - */ -public interface FTPFileFilter { - /** - * Checks if an FTPFile entry should be included or not. - * - * @param file entry to be checked for inclusion. May be null. - * @return true if the file is to be included, false otherwise - */ - public boolean accept(FTPFile file); -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPFileFilters.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPFileFilters.java deleted file mode 100644 index 40a59a99..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPFileFilters.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -/** - * Implements some simple FTPFileFilter classes. - * - * @since 2.2 - */ -public class FTPFileFilters { - - /** - * Accepts all FTPFile entries, including null. - */ - public static final FTPFileFilter ALL = new FTPFileFilter() { - @Override public boolean accept(FTPFile file) { - return true; - } - }; - - /** - * Accepts all non-null FTPFile entries. - */ - public static final FTPFileFilter NON_NULL = new FTPFileFilter() { - @Override public boolean accept(FTPFile file) { - return file != null; - } - }; - - /** - * Accepts all (non-null) FTPFile directory entries. - */ - public static final FTPFileFilter DIRECTORIES = new FTPFileFilter() { - @Override public boolean accept(FTPFile file) { - return file != null && file.isDirectory(); - } - }; -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPHTTPClient.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPHTTPClient.java deleted file mode 100644 index 0304e427..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPHTTPClient.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.Reader; -import java.io.UnsupportedEncodingException; -import java.net.Inet6Address; -import java.net.Socket; -import java.net.SocketException; -import java.util.ArrayList; -import java.util.List; - -import aria.apache.commons.net.util.Base64; - -/** - * Experimental attempt at FTP client that tunnels over an HTTP proxy connection. - * - * @since 2.2 - */ -public class FTPHTTPClient extends FTPClient { - private final String proxyHost; - private final int proxyPort; - private final String proxyUsername; - private final String proxyPassword; - - private static final byte[] CRLF = { '\r', '\n' }; - private final Base64 base64 = new Base64(); - - private String tunnelHost; // Save the host when setting up a tunnel (needed for EPSV) - - public FTPHTTPClient(String proxyHost, int proxyPort, String proxyUser, String proxyPass) { - this.proxyHost = proxyHost; - this.proxyPort = proxyPort; - this.proxyUsername = proxyUser; - this.proxyPassword = proxyPass; - this.tunnelHost = null; - } - - public FTPHTTPClient(String proxyHost, int proxyPort) { - this(proxyHost, proxyPort, null, null); - } - - /** - * {@inheritDoc} - * - * @throws IllegalStateException if connection mode is not passive - * @deprecated (3.3) Use {@link FTPClient#_openDataConnection_(FTPCmd, String)} instead - */ - // Kept to maintain binary compatibility - // Not strictly necessary, but Clirr complains even though there is a super-impl - @Override @Deprecated protected Socket _openDataConnection_(int command, String arg) - throws IOException { - return super._openDataConnection_(command, arg); - } - - /** - * {@inheritDoc} - * - * @throws IllegalStateException if connection mode is not passive - * @since 3.1 - */ - @Override protected Socket _openDataConnection_(String command, String arg) throws IOException { - //Force local passive mode, active mode not supported by through proxy - if (getDataConnectionMode() != PASSIVE_LOCAL_DATA_CONNECTION_MODE) { - throw new IllegalStateException("Only passive connection mode supported"); - } - - final boolean isInet6Address = getRemoteAddress() instanceof Inet6Address; - String passiveHost = null; - - boolean attemptEPSV = isUseEPSVwithIPv4() || isInet6Address; - if (attemptEPSV && epsv() == FTPReply.ENTERING_EPSV_MODE) { - _parseExtendedPassiveModeReply(_replyLines.get(0)); - passiveHost = this.tunnelHost; - } else { - if (isInet6Address) { - return null; // Must use EPSV for IPV6 - } - // If EPSV failed on IPV4, revert to PASV - if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) { - return null; - } - _parsePassiveModeReply(_replyLines.get(0)); - passiveHost = this.getPassiveHost(); - } - - Socket socket = _socketFactory_.createSocket(proxyHost, proxyPort); - InputStream is = socket.getInputStream(); - OutputStream os = socket.getOutputStream(); - tunnelHandshake(passiveHost, this.getPassivePort(), is, os); - if ((getRestartOffset() > 0) && !restart(getRestartOffset())) { - socket.close(); - return null; - } - - if (!FTPReply.isPositivePreliminary(sendCommand(command, arg))) { - socket.close(); - return null; - } - - return socket; - } - - @Override public void connect(String host, int port) throws SocketException, IOException { - - _socket_ = _socketFactory_.createSocket(proxyHost, proxyPort); - _input_ = _socket_.getInputStream(); - _output_ = _socket_.getOutputStream(); - Reader socketIsReader; - try { - socketIsReader = tunnelHandshake(host, port, _input_, _output_); - } catch (Exception e) { - IOException ioe = new IOException("Could not connect to " + host + " using port " + port); - ioe.initCause(e); - throw ioe; - } - super._connectAction_(socketIsReader); - } - - private BufferedReader tunnelHandshake(String host, int port, InputStream input, - OutputStream output) throws IOException, UnsupportedEncodingException { - final String connectString = "CONNECT " + host + ":" + port + " HTTP/1.1"; - final String hostString = "Host: " + host + ":" + port; - - this.tunnelHost = host; - output.write(connectString.getBytes("UTF-8")); // TODO what is the correct encoding? - output.write(CRLF); - output.write(hostString.getBytes("UTF-8")); - output.write(CRLF); - - if (proxyUsername != null && proxyPassword != null) { - final String auth = proxyUsername + ":" + proxyPassword; - final String header = - "Proxy-Authorization: Basic " + base64.encodeToString(auth.getBytes("UTF-8")); - output.write(header.getBytes("UTF-8")); - } - output.write(CRLF); - - List response = new ArrayList(); - BufferedReader reader = new BufferedReader(new InputStreamReader(input, getCharset())); - - for (String line = reader.readLine(); line != null && line.length() > 0; - line = reader.readLine()) { - response.add(line); - } - - int size = response.size(); - if (size == 0) { - throw new IOException("No response from proxy"); - } - - String code = null; - String resp = response.get(0); - if (resp.startsWith("HTTP/") && resp.length() >= 12) { - code = resp.substring(9, 12); - } else { - throw new IOException("Invalid response from proxy: " + resp); - } - - if (!"200".equals(code)) { - StringBuilder msg = new StringBuilder(); - msg.append("HTTPTunnelConnector: connection failed\r\n"); - msg.append("Response received from the proxy:\r\n"); - for (String line : response) { - msg.append(line); - msg.append("\r\n"); - } - throw new IOException(msg.toString()); - } - return reader; - } -} - - diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPListParseEngine.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPListParseEngine.java deleted file mode 100644 index 51e117e5..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPListParseEngine.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; - -import aria.apache.commons.net.util.Charsets; - -/** - * This class handles the entire process of parsing a listing of - * file entries from the server. - *

- * This object defines a two-part parsing mechanism. - *

- * The first part is comprised of reading the raw input into an internal - * list of strings. Every item in this list corresponds to an actual - * file. All extraneous matter emitted by the server will have been - * removed by the end of this phase. This is accomplished in conjunction - * with the FTPFileEntryParser associated with this engine, by calling - * its methods readNextEntry() - which handles the issue of - * what delimits one entry from another, usually but not always a line - * feed and preParse() - which handles removal of - * extraneous matter such as the preliminary lines of a listing, removal - * of duplicates on versioning systems, etc. - *

- * The second part is composed of the actual parsing, again in conjunction - * with the particular parser used by this engine. This is controlled - * by an iterator over the internal list of strings. This may be done - * either in block mode, by calling the getNext() and - * getPrevious() methods to provide "paged" output of less - * than the whole list at one time, or by calling the - * getFiles() method to return the entire list. - *

- * Examples: - *

- * Paged access: - *

- *    FTPClient f=FTPClient();
- *    f.connect(server);
- *    f.login(username, password);
- *    FTPListParseEngine engine = f.initiateListParsing(directory);
- *
- *    while (engine.hasNext()) {
- *       FTPFile[] files = engine.getNext(25);  // "page size" you want
- *       //do whatever you want with these files, display them, etc.
- *       //expensive FTPFile objects not created until needed.
- *    }
- * 
- *

- * For unpaged access, simply use FTPClient.listFiles(). That method - * uses this class transparently. - * - * @version $Id: FTPListParseEngine.java 1747119 2016-06-07 02:22:24Z ggregory $ - */ -public class FTPListParseEngine { - private List entries = new LinkedList(); - private ListIterator _internalIterator = entries.listIterator(); - - private final FTPFileEntryParser parser; - // Should invalid files (parse failures) be allowed? - private final boolean saveUnparseableEntries; - - public FTPListParseEngine(FTPFileEntryParser parser) { - this(parser, null); - } - - /** - * Intended for use by FTPClient only - * - * @since 3.4 - */ - FTPListParseEngine(FTPFileEntryParser parser, FTPClientConfig configuration) { - this.parser = parser; - if (configuration != null) { - this.saveUnparseableEntries = configuration.getUnparseableEntries(); - } else { - this.saveUnparseableEntries = false; - } - } - - /** - * handle the initial reading and preparsing of the list returned by - * the server. After this method has completed, this object will contain - * a list of unparsed entries (Strings) each referring to a unique file - * on the server. - * - * @param stream input stream provided by the server socket. - * @param encoding the encoding to be used for reading the stream - * @throws IOException thrown on any failure to read from the sever. - */ - public void readServerList(InputStream stream, String encoding) throws IOException { - this.entries = new LinkedList(); - readStream(stream, encoding); - this.parser.preParse(this.entries); - resetIterator(); - } - - /** - * Internal method for reading the input into the entries list. - * After this method has completed, entries will contain a - * collection of entries (as defined by - * FTPFileEntryParser.readNextEntry()), but this may contain - * various non-entry preliminary lines from the server output, duplicates, - * and other data that will not be part of the final listing. - * - * @param stream The socket stream on which the input will be read. - * @param encoding The encoding to use. - * @throws IOException thrown on any failure to read the stream - */ - private void readStream(InputStream stream, String encoding) throws IOException { - BufferedReader reader = - new BufferedReader(new InputStreamReader(stream, Charsets.toCharset(encoding))); - - String line = this.parser.readNextEntry(reader); - - while (line != null) { - this.entries.add(line); - line = this.parser.readNextEntry(reader); - } - reader.close(); - } - - /** - * Returns an array of at most quantityRequested FTPFile - * objects starting at this object's internal iterator's current position. - * If fewer than quantityRequested such - * elements are available, the returned array will have a length equal - * to the number of entries at and after after the current position. - * If no such entries are found, this array will have a length of 0. - * - * After this method is called this object's internal iterator is advanced - * by a number of positions equal to the size of the array returned. - * - * @param quantityRequested the maximum number of entries we want to get. - * @return an array of at most quantityRequested FTPFile - * objects starting at the current position of this iterator within its - * list and at least the number of elements which exist in the list at - * and after its current position. - *

- * NOTE: This array may contain null members if any of the - * individual file listings failed to parse. The caller should - * check each entry for null before referencing it. - */ - public FTPFile[] getNext(int quantityRequested) { - List tmpResults = new LinkedList(); - int count = quantityRequested; - while (count > 0 && this._internalIterator.hasNext()) { - String entry = this._internalIterator.next(); - FTPFile temp = this.parser.parseFTPEntry(entry); - if (temp == null && saveUnparseableEntries) { - temp = new FTPFile(entry); - } - tmpResults.add(temp); - count--; - } - return tmpResults.toArray(new FTPFile[tmpResults.size()]); - } - - /** - * Returns an array of at most quantityRequested FTPFile - * objects starting at this object's internal iterator's current position, - * and working back toward the beginning. - * - * If fewer than quantityRequested such - * elements are available, the returned array will have a length equal - * to the number of entries at and after after the current position. - * If no such entries are found, this array will have a length of 0. - * - * After this method is called this object's internal iterator is moved - * back by a number of positions equal to the size of the array returned. - * - * @param quantityRequested the maximum number of entries we want to get. - * @return an array of at most quantityRequested FTPFile - * objects starting at the current position of this iterator within its - * list and at least the number of elements which exist in the list at - * and after its current position. This array will be in the same order - * as the underlying list (not reversed). - *

- * NOTE: This array may contain null members if any of the - * individual file listings failed to parse. The caller should - * check each entry for null before referencing it. - */ - public FTPFile[] getPrevious(int quantityRequested) { - List tmpResults = new LinkedList(); - int count = quantityRequested; - while (count > 0 && this._internalIterator.hasPrevious()) { - String entry = this._internalIterator.previous(); - FTPFile temp = this.parser.parseFTPEntry(entry); - if (temp == null && saveUnparseableEntries) { - temp = new FTPFile(entry); - } - tmpResults.add(0, temp); - count--; - } - return tmpResults.toArray(new FTPFile[tmpResults.size()]); - } - - /** - * Returns an array of FTPFile objects containing the whole list of - * files returned by the server as read by this object's parser. - * - * @return an array of FTPFile objects containing the whole list of - * files returned by the server as read by this object's parser. - * None of the entries will be null - * @throws IOException - not ever thrown, may be removed in a later release - */ - public FTPFile[] getFiles() throws IOException // TODO remove; not actually thrown - { - return getFiles(FTPFileFilters.NON_NULL); - } - - /** - * Returns an array of FTPFile objects containing the whole list of - * files returned by the server as read by this object's parser. - * The files are filtered before being added to the array. - * - * @param filter FTPFileFilter, must not be null. - * @return an array of FTPFile objects containing the whole list of - * files returned by the server as read by this object's parser. - *

- * NOTE: This array may contain null members if any of the - * individual file listings failed to parse. The caller should - * check each entry for null before referencing it, or use the - * a filter such as {@link FTPFileFilters#NON_NULL} which does not - * allow null entries. - * @throws IOException - not ever thrown, may be removed in a later release - * @since 2.2 - */ - public FTPFile[] getFiles(FTPFileFilter filter) - throws IOException // TODO remove; not actually thrown - { - List tmpResults = new ArrayList(); - Iterator iter = this.entries.iterator(); - while (iter.hasNext()) { - String entry = iter.next(); - FTPFile temp = this.parser.parseFTPEntry(entry); - if (temp == null && saveUnparseableEntries) { - temp = new FTPFile(entry); - } - if (filter.accept(temp)) { - tmpResults.add(temp); - } - } - return tmpResults.toArray(new FTPFile[tmpResults.size()]); - } - - /** - * convenience method to allow clients to know whether this object's - * internal iterator's current position is at the end of the list. - * - * @return true if internal iterator is not at end of list, false - * otherwise. - */ - public boolean hasNext() { - return _internalIterator.hasNext(); - } - - /** - * convenience method to allow clients to know whether this object's - * internal iterator's current position is at the beginning of the list. - * - * @return true if internal iterator is not at beginning of list, false - * otherwise. - */ - public boolean hasPrevious() { - return _internalIterator.hasPrevious(); - } - - /** - * resets this object's internal iterator to the beginning of the list. - */ - public void resetIterator() { - this._internalIterator = this.entries.listIterator(); - } - - // DEPRECATED METHODS - for API compatibility only - DO NOT USE - - /** - * Do not use. - * - * @param stream the stream from which to read - * @throws IOException on error - * @deprecated use {@link #readServerList(InputStream, String)} instead - */ - @Deprecated public void readServerList(InputStream stream) throws IOException { - readServerList(stream, null); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPReply.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPReply.java deleted file mode 100644 index 991cb93d..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPReply.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -/*** - * FTPReply stores a set of constants for FTP reply codes. To interpret - * the meaning of the codes, familiarity with RFC 959 is assumed. - * The mnemonic constant names are transcriptions from the code descriptions - * of RFC 959. - *

- * TODO replace with an enum - ***/ - -public final class FTPReply { - - public static final int RESTART_MARKER = 110; - public static final int SERVICE_NOT_READY = 120; - public static final int DATA_CONNECTION_ALREADY_OPEN = 125; - public static final int FILE_STATUS_OK = 150; - public static final int COMMAND_OK = 200; - public static final int COMMAND_IS_SUPERFLUOUS = 202; - public static final int SYSTEM_STATUS = 211; - public static final int DIRECTORY_STATUS = 212; - public static final int FILE_STATUS = 213; - public static final int HELP_MESSAGE = 214; - public static final int NAME_SYSTEM_TYPE = 215; - public static final int SERVICE_READY = 220; - public static final int SERVICE_CLOSING_CONTROL_CONNECTION = 221; - public static final int DATA_CONNECTION_OPEN = 225; - public static final int CLOSING_DATA_CONNECTION = 226; - public static final int ENTERING_PASSIVE_MODE = 227; - /** @since 2.2 */ - public static final int ENTERING_EPSV_MODE = 229; - public static final int USER_LOGGED_IN = 230; - public static final int FILE_ACTION_OK = 250; - public static final int PATHNAME_CREATED = 257; - public static final int NEED_PASSWORD = 331; - public static final int NEED_ACCOUNT = 332; - public static final int FILE_ACTION_PENDING = 350; - public static final int SERVICE_NOT_AVAILABLE = 421; - public static final int CANNOT_OPEN_DATA_CONNECTION = 425; - public static final int TRANSFER_ABORTED = 426; - public static final int FILE_ACTION_NOT_TAKEN = 450; - public static final int ACTION_ABORTED = 451; - public static final int INSUFFICIENT_STORAGE = 452; - public static final int UNRECOGNIZED_COMMAND = 500; - public static final int SYNTAX_ERROR_IN_ARGUMENTS = 501; - public static final int COMMAND_NOT_IMPLEMENTED = 502; - public static final int BAD_COMMAND_SEQUENCE = 503; - public static final int COMMAND_NOT_IMPLEMENTED_FOR_PARAMETER = 504; - public static final int NOT_LOGGED_IN = 530; - public static final int NEED_ACCOUNT_FOR_STORING_FILES = 532; - public static final int FILE_UNAVAILABLE = 550; - public static final int PAGE_TYPE_UNKNOWN = 551; - public static final int STORAGE_ALLOCATION_EXCEEDED = 552; - public static final int FILE_NAME_NOT_ALLOWED = 553; - - // FTPS Reply Codes - - /** @since 2.0 */ - public static final int SECURITY_DATA_EXCHANGE_COMPLETE = 234; - /** @since 2.0 */ - public static final int SECURITY_DATA_EXCHANGE_SUCCESSFULLY = 235; - /** @since 2.0 */ - public static final int SECURITY_MECHANISM_IS_OK = 334; - /** @since 2.0 */ - public static final int SECURITY_DATA_IS_ACCEPTABLE = 335; - /** @since 2.0 */ - public static final int UNAVAILABLE_RESOURCE = 431; - /** @since 2.2 */ - public static final int BAD_TLS_NEGOTIATION_OR_DATA_ENCRYPTION_REQUIRED = 522; - /** @since 2.0 */ - public static final int DENIED_FOR_POLICY_REASONS = 533; - /** @since 2.0 */ - public static final int REQUEST_DENIED = 534; - /** @since 2.0 */ - public static final int FAILED_SECURITY_CHECK = 535; - /** @since 2.0 */ - public static final int REQUESTED_PROT_LEVEL_NOT_SUPPORTED = 536; - - // IPv6 error codes - // Note this is also used as an FTPS error code reply - /** @since 2.2 */ - public static final int EXTENDED_PORT_FAILURE = 522; - - // Cannot be instantiated - private FTPReply() { - } - - /*** - * Determine if a reply code is a positive preliminary response. All - * codes beginning with a 1 are positive preliminary responses. - * Postitive preliminary responses are used to indicate tentative success. - * No further commands can be issued to the FTP server after a positive - * preliminary response until a follow up response is received from the - * server. - * - * @param reply The reply code to test. - * @return True if a reply code is a postive preliminary response, false - * if not. - ***/ - public static boolean isPositivePreliminary(int reply) { - return (reply >= 100 && reply < 200); - } - - /*** - * Determine if a reply code is a positive completion response. All - * codes beginning with a 2 are positive completion responses. - * The FTP server will send a positive completion response on the final - * successful completion of a command. - * - * @param reply The reply code to test. - * @return True if a reply code is a postive completion response, false - * if not. - ***/ - public static boolean isPositiveCompletion(int reply) { - return (reply >= 200 && reply < 300); - } - - /*** - * Determine if a reply code is a positive intermediate response. All - * codes beginning with a 3 are positive intermediate responses. - * The FTP server will send a positive intermediate response on the - * successful completion of one part of a multi-part sequence of - * commands. For example, after a successful USER command, a positive - * intermediate response will be sent to indicate that the server is - * ready for the PASS command. - * - * @param reply The reply code to test. - * @return True if a reply code is a postive intermediate response, false - * if not. - ***/ - public static boolean isPositiveIntermediate(int reply) { - return (reply >= 300 && reply < 400); - } - - /*** - * Determine if a reply code is a negative transient response. All - * codes beginning with a 4 are negative transient responses. - * The FTP server will send a negative transient response on the - * failure of a command that can be reattempted with success. - * - * @param reply The reply code to test. - * @return True if a reply code is a negative transient response, false - * if not. - ***/ - public static boolean isNegativeTransient(int reply) { - return (reply >= 400 && reply < 500); - } - - /*** - * Determine if a reply code is a negative permanent response. All - * codes beginning with a 5 are negative permanent responses. - * The FTP server will send a negative permanent response on the - * failure of a command that cannot be reattempted with success. - * - * @param reply The reply code to test. - * @return True if a reply code is a negative permanent response, false - * if not. - ***/ - public static boolean isNegativePermanent(int reply) { - return (reply >= 500 && reply < 600); - } - - /** - * Determine if a reply code is a protected response. - * - * @param reply The reply code to test. - * @return True if a reply code is a protected response, false - * if not. - * @since 3.0 - */ - public static boolean isProtectedReplyCode(int reply) { - // actually, only 3 protected reply codes are - // defined in RFC 2228: 631, 632 and 633. - return (reply >= 600 && reply < 700); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPSClient.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPSClient.java deleted file mode 100644 index 7f79e98b..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPSClient.java +++ /dev/null @@ -1,931 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -import aria.apache.commons.net.SocketClient; -import aria.apache.commons.net.util.KeyManagerUtils; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.net.Socket; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLHandshakeException; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; - -import aria.apache.commons.net.util.Base64; -import aria.apache.commons.net.util.SSLContextUtils; -import aria.apache.commons.net.util.SSLSocketUtils; -import aria.apache.commons.net.util.TrustManagerUtils; - -/** - * FTP over SSL processing. If desired, the JVM property -Djavax.net.debug=all can be used to - * see wire-level SSL details. - * - * Warning: the hostname is not verified against the certificate by default, use - * {@link #setHostnameVerifier(HostnameVerifier)} or {@link #setEndpointCheckingEnabled(boolean)} - * (on Java 1.7+) to enable verification. Verification is only performed on client mode connections. - * - * @version $Id: FTPSClient.java 1747829 2016-06-11 00:57:57Z sebb $ - * @since 2.0 - */ -public class FTPSClient extends FTPClient { - - // From http://www.iana.org/assignments/port-numbers - - // ftps-data 989/tcp ftp protocol, data, over TLS/SSL - // ftps-data 989/udp ftp protocol, data, over TLS/SSL - // ftps 990/tcp ftp protocol, control, over TLS/SSL - // ftps 990/udp ftp protocol, control, over TLS/SSL - - public static final int DEFAULT_FTPS_DATA_PORT = 989; - public static final int DEFAULT_FTPS_PORT = 990; - - /** The value that I can set in PROT command (C = Clear, P = Protected) */ - private static final String[] PROT_COMMAND_VALUE = { "C", "E", "S", "P" }; - /** Default PROT Command */ - private static final String DEFAULT_PROT = "C"; - /** Default secure socket protocol name, i.e. TLS */ - private static final String DEFAULT_PROTOCOL = "TLS"; - - /** The AUTH (Authentication/Security Mechanism) command. */ - private static final String CMD_AUTH = "AUTH"; - /** The ADAT (Authentication/Security Data) command. */ - private static final String CMD_ADAT = "ADAT"; - /** The PROT (Data Channel Protection Level) command. */ - private static final String CMD_PROT = "PROT"; - /** The PBSZ (Protection Buffer Size) command. */ - private static final String CMD_PBSZ = "PBSZ"; - /** The MIC (Integrity Protected Command) command. */ - private static final String CMD_MIC = "MIC"; - /** The CONF (Confidentiality Protected Command) command. */ - private static final String CMD_CONF = "CONF"; - /** The ENC (Privacy Protected Command) command. */ - private static final String CMD_ENC = "ENC"; - /** The CCC (Clear Command Channel) command. */ - private static final String CMD_CCC = "CCC"; - - /** The security mode. (True - Implicit Mode / False - Explicit Mode) */ - private final boolean isImplicit; - /** The secure socket protocol to be used, e.g. SSL/TLS. */ - private final String protocol; - /** The AUTH Command value */ - private String auth = DEFAULT_PROTOCOL; - /** The context object. */ - private SSLContext context; - /** The socket object. */ - private Socket plainSocket; - /** Controls whether a new SSL session may be established by this socket. Default true. */ - private boolean isCreation = true; - /** The use client mode flag. */ - private boolean isClientMode = true; - /** The need client auth flag. */ - private boolean isNeedClientAuth = false; - /** The want client auth flag. */ - private boolean isWantClientAuth = false; - /** The cipher suites */ - private String[] suites = null; - /** The protocol versions */ - private String[] protocols = null; - - /** - * The FTPS {@link TrustManager} implementation, default validate only - * {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}. - */ - private TrustManager trustManager = TrustManagerUtils.getValidateServerCertificateTrustManager(); - - /** The {@link KeyManager}, default null (i.e. use system default). */ - private KeyManager keyManager = null; - - /** The {@link HostnameVerifier} to use post-TLS, default null (i.e. no verification). */ - private HostnameVerifier hostnameVerifier = null; - - /** Use Java 1.7+ HTTPS Endpoint Identification Algorithim. */ - private boolean tlsEndpointChecking; - - /** - * Constructor for FTPSClient, calls {@link #FTPSClient(String, boolean)}. - * - * Sets protocol to {@link #DEFAULT_PROTOCOL} - i.e. TLS - and security mode to explicit - * (isImplicit = false) - */ - public FTPSClient() { - this(DEFAULT_PROTOCOL, false); - } - - /** - * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS - * Calls {@link #FTPSClient(String, boolean)} - * - * @param isImplicit The security mode (Implicit/Explicit). - */ - public FTPSClient(boolean isImplicit) { - this(DEFAULT_PROTOCOL, isImplicit); - } - - /** - * Constructor for FTPSClient, using explict mode, calls {@link #FTPSClient(String, boolean)}. - * - * @param protocol the protocol to use - */ - public FTPSClient(String protocol) { - this(protocol, false); - } - - /** - * Constructor for FTPSClient allowing specification of protocol - * and security mode. If isImplicit is true, the port is set to - * {@link #DEFAULT_FTPS_PORT} i.e. 990. - * The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()} - * - * @param protocol the protocol - * @param isImplicit The security mode(Implicit/Explicit). - */ - public FTPSClient(String protocol, boolean isImplicit) { - super(); - this.protocol = protocol; - this.isImplicit = isImplicit; - if (isImplicit) { - setDefaultPort(DEFAULT_FTPS_PORT); - } - } - - /** - * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS - * The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()} - * - * @param isImplicit The security mode(Implicit/Explicit). - * @param context A pre-configured SSL Context - */ - public FTPSClient(boolean isImplicit, SSLContext context) { - this(DEFAULT_PROTOCOL, isImplicit); - this.context = context; - } - - /** - * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS - * and isImplicit {@code false} - * Calls {@link #FTPSClient(boolean, SSLContext)} - * - * @param context A pre-configured SSL Context - */ - public FTPSClient(SSLContext context) { - this(false, context); - } - - /** - * Set AUTH command use value. - * This processing is done before connected processing. - * - * @param auth AUTH command use value. - */ - public void setAuthValue(String auth) { - this.auth = auth; - } - - /** - * Return AUTH command use value. - * - * @return AUTH command use value. - */ - public String getAuthValue() { - return this.auth; - } - - /** - * Because there are so many connect() methods, - * the _connectAction_() method is provided as a means of performing - * some action immediately after establishing a connection, - * rather than reimplementing all of the connect() methods. - * - * @throws IOException If it throw by _connectAction_. - * @see SocketClient#_connectAction_() - */ - @Override protected void _connectAction_() throws IOException { - // Implicit mode. - if (isImplicit) { - sslNegotiation(); - } - super._connectAction_(); - // Explicit mode. - if (!isImplicit) { - execAUTH(); - sslNegotiation(); - } - } - - /** - * AUTH command. - * - * @throws SSLException If it server reply code not equal "234" and "334". - * @throws IOException If an I/O error occurs while either sending - * the command. - */ - protected void execAUTH() throws SSLException, IOException { - int replyCode = sendCommand(CMD_AUTH, auth); - if (FTPReply.SECURITY_MECHANISM_IS_OK == replyCode) { - // replyCode = 334 - // I carry out an ADAT command. - } else if (FTPReply.SECURITY_DATA_EXCHANGE_COMPLETE != replyCode) { - throw new SSLException(getReplyString()); - } - } - - /** - * Performs a lazy init of the SSL context - * - * @throws IOException - */ - private void initSslContext() throws IOException { - if (context == null) { - context = SSLContextUtils.createSSLContext(protocol, getKeyManager(), getTrustManager()); - } - } - - /** - * SSL/TLS negotiation. Acquires an SSL socket of a control - * connection and carries out handshake processing. - * - * @throws IOException If server negotiation fails - */ - protected void sslNegotiation() throws IOException { - plainSocket = _socket_; - initSslContext(); - - SSLSocketFactory ssf = context.getSocketFactory(); - String host = (_hostname_ != null) ? _hostname_ : getRemoteAddress().getHostAddress(); - int port = _socket_.getPort(); - SSLSocket socket = (SSLSocket) ssf.createSocket(_socket_, host, port, false); - socket.setEnableSessionCreation(isCreation); - socket.setUseClientMode(isClientMode); - - // client mode - if (isClientMode) { - if (tlsEndpointChecking) { - SSLSocketUtils.enableEndpointNameVerification(socket); - } - } else { // server mode - socket.setNeedClientAuth(isNeedClientAuth); - socket.setWantClientAuth(isWantClientAuth); - } - - if (protocols != null) { - socket.setEnabledProtocols(protocols); - } - if (suites != null) { - socket.setEnabledCipherSuites(suites); - } - socket.startHandshake(); - - // TODO the following setup appears to duplicate that in the super class methods - _socket_ = socket; - _controlInput_ = - new BufferedReader(new InputStreamReader(socket.getInputStream(), getControlEncoding())); - _controlOutput_ = - new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), getControlEncoding())); - - if (isClientMode) { - if (hostnameVerifier != null && !hostnameVerifier.verify(host, socket.getSession())) { - throw new SSLHandshakeException("Hostname doesn't match certificate"); - } - } - } - - /** - * Get the {@link KeyManager} instance. - * - * @return The {@link KeyManager} instance - */ - private KeyManager getKeyManager() { - return keyManager; - } - - /** - * Set a {@link KeyManager} to use - * - * @param keyManager The KeyManager implementation to set. - * @see KeyManagerUtils - */ - public void setKeyManager(KeyManager keyManager) { - this.keyManager = keyManager; - } - - /** - * Controls whether a new SSL session may be established by this socket. - * - * @param isCreation The established socket flag. - */ - public void setEnabledSessionCreation(boolean isCreation) { - this.isCreation = isCreation; - } - - /** - * Returns true if new SSL sessions may be established by this socket. - * When the underlying {@link Socket} instance is not SSL-enabled (i.e. an - * instance of {@link SSLSocket} with {@link SSLSocket}{@link #getEnableSessionCreation()}) - * enabled, - * this returns False. - * - * @return true - Indicates that sessions may be created; - * this is the default. - * false - indicates that an existing session must be resumed. - */ - public boolean getEnableSessionCreation() { - if (_socket_ instanceof SSLSocket) { - return ((SSLSocket) _socket_).getEnableSessionCreation(); - } - return false; - } - - /** - * Configures the socket to require client authentication. - * - * @param isNeedClientAuth The need client auth flag. - */ - public void setNeedClientAuth(boolean isNeedClientAuth) { - this.isNeedClientAuth = isNeedClientAuth; - } - - /** - * Returns true if the socket will require client authentication. - * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. - * - * @return true - If the server mode socket should request - * that the client authenticate itself. - */ - public boolean getNeedClientAuth() { - if (_socket_ instanceof SSLSocket) { - return ((SSLSocket) _socket_).getNeedClientAuth(); - } - return false; - } - - /** - * Configures the socket to request client authentication, - * but only if such a request is appropriate to the cipher - * suite negotiated. - * - * @param isWantClientAuth The want client auth flag. - */ - public void setWantClientAuth(boolean isWantClientAuth) { - this.isWantClientAuth = isWantClientAuth; - } - - /** - * Returns true if the socket will request client authentication. - * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. - * - * @return true - If the server mode socket should request - * that the client authenticate itself. - */ - public boolean getWantClientAuth() { - if (_socket_ instanceof SSLSocket) { - return ((SSLSocket) _socket_).getWantClientAuth(); - } - return false; - } - - /** - * Configures the socket to use client (or server) mode in its first - * handshake. - * - * @param isClientMode The use client mode flag. - */ - public void setUseClientMode(boolean isClientMode) { - this.isClientMode = isClientMode; - } - - /** - * Returns true if the socket is set to use client mode - * in its first handshake. - * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. - * - * @return true - If the socket should start its first handshake - * in "client" mode. - */ - public boolean getUseClientMode() { - if (_socket_ instanceof SSLSocket) { - return ((SSLSocket) _socket_).getUseClientMode(); - } - return false; - } - - /** - * Controls which particular cipher suites are enabled for use on this - * connection. Called before server negotiation. - * - * @param cipherSuites The cipher suites. - */ - public void setEnabledCipherSuites(String[] cipherSuites) { - suites = new String[cipherSuites.length]; - System.arraycopy(cipherSuites, 0, suites, 0, cipherSuites.length); - } - - /** - * Returns the names of the cipher suites which could be enabled - * for use on this connection. - * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null. - * - * @return An array of cipher suite names, or null - */ - public String[] getEnabledCipherSuites() { - if (_socket_ instanceof SSLSocket) { - return ((SSLSocket) _socket_).getEnabledCipherSuites(); - } - return null; - } - - /** - * Controls which particular protocol versions are enabled for use on this - * connection. I perform setting before a server negotiation. - * - * @param protocolVersions The protocol versions. - */ - public void setEnabledProtocols(String[] protocolVersions) { - protocols = new String[protocolVersions.length]; - System.arraycopy(protocolVersions, 0, protocols, 0, protocolVersions.length); - } - - /** - * Returns the names of the protocol versions which are currently - * enabled for use on this connection. - * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null. - * - * @return An array of protocols, or null - */ - public String[] getEnabledProtocols() { - if (_socket_ instanceof SSLSocket) { - return ((SSLSocket) _socket_).getEnabledProtocols(); - } - return null; - } - - /** - * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. - * - * @param pbsz Protection Buffer Size. - * @throws SSLException If the server reply code does not equal "200". - * @throws IOException If an I/O error occurs while sending - * the command. - * @see #parsePBSZ(long) - */ - public void execPBSZ(long pbsz) throws SSLException, IOException { - if (pbsz < 0 || 4294967295L < pbsz) { // 32-bit unsigned number - throw new IllegalArgumentException(); - } - int status = sendCommand(CMD_PBSZ, String.valueOf(pbsz)); - if (FTPReply.COMMAND_OK != status) { - throw new SSLException(getReplyString()); - } - } - - /** - * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. - * Issues the command and parses the response to return the negotiated value. - * - * @param pbsz Protection Buffer Size. - * @return the negotiated value. - * @throws SSLException If the server reply code does not equal "200". - * @throws IOException If an I/O error occurs while sending - * the command. - * @see #execPBSZ(long) - * @since 3.0 - */ - public long parsePBSZ(long pbsz) throws SSLException, IOException { - execPBSZ(pbsz); - long minvalue = pbsz; - String remainder = extractPrefixedData("PBSZ=", getReplyString()); - if (remainder != null) { - long replysz = Long.parseLong(remainder); - if (replysz < minvalue) { - minvalue = replysz; - } - } - return minvalue; - } - - /** - * PROT command. - *

    - *
  • C - Clear
  • - *
  • S - Safe(SSL protocol only)
  • - *
  • E - Confidential(SSL protocol only)
  • - *
  • P - Private
  • - *
- * N.B. the method calls - * {@link #setSocketFactory(javax.net.SocketFactory)} and - * {@link #setServerSocketFactory(javax.net.ServerSocketFactory)} - * - * @param prot Data Channel Protection Level, if {@code null}, use {@link #DEFAULT_PROT}. - * @throws SSLException If the server reply code does not equal {@code 200}. - * @throws IOException If an I/O error occurs while sending - * the command. - */ - public void execPROT(String prot) throws SSLException, IOException { - if (prot == null) { - prot = DEFAULT_PROT; - } - if (!checkPROTValue(prot)) { - throw new IllegalArgumentException(); - } - if (FTPReply.COMMAND_OK != sendCommand(CMD_PROT, prot)) { - throw new SSLException(getReplyString()); - } - if (DEFAULT_PROT.equals(prot)) { - setSocketFactory(null); - setServerSocketFactory(null); - } else { - setSocketFactory(new FTPSSocketFactory(context)); - setServerSocketFactory(new FTPSServerSocketFactory(context)); - initSslContext(); - } - } - - /** - * Check the value that can be set in PROT Command value. - * - * @param prot Data Channel Protection Level. - * @return True - A set point is right / False - A set point is not right - */ - private boolean checkPROTValue(String prot) { - for (String element : PROT_COMMAND_VALUE) { - if (element.equals(prot)) { - return true; - } - } - return false; - } - - /** - * Send an FTP command. - * A successful CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} - * instance to be assigned to a plain {@link Socket} - * - * @param command The FTP command. - * @return server reply. - * @throws IOException If an I/O error occurs while sending the command. - * @throws SSLException if a CCC command fails - * @see FTP#sendCommand(String) - */ - // Would like to remove this method, but that will break any existing clients that are using CCC - @Override public int sendCommand(String command, String args) throws IOException { - int repCode = super.sendCommand(command, args); - /* If CCC is issued, restore socket i/o streams to unsecured versions */ - if (CMD_CCC.equals(command)) { - if (FTPReply.COMMAND_OK == repCode) { - _socket_.close(); - _socket_ = plainSocket; - _controlInput_ = new BufferedReader( - new InputStreamReader(_socket_.getInputStream(), getControlEncoding())); - _controlOutput_ = new BufferedWriter( - new OutputStreamWriter(_socket_.getOutputStream(), getControlEncoding())); - } else { - throw new SSLException(getReplyString()); - } - } - return repCode; - } - - /** - * Returns a socket of the data connection. - * Wrapped as an {@link SSLSocket}, which carries out handshake processing. - * - * @param command The int representation of the FTP command to send. - * @param arg The arguments to the FTP command. - * If this parameter is set to null, then the command is sent with - * no arguments. - * @return corresponding to the established data connection. - * Null is returned if an FTP protocol error is reported at any point - * during the establishment and initialization of the connection. - * @throws IOException If there is any problem with the connection. - * @see FTPClient#_openDataConnection_(int, String) - * @deprecated (3.3) Use {@link FTPClient#_openDataConnection_(FTPCmd, String)} instead - */ - @Override - // Strictly speaking this is not needed, but it works round a Clirr bug - // So rather than invoke the parent code, we do it here - @Deprecated protected Socket _openDataConnection_(int command, String arg) throws IOException { - return _openDataConnection_(FTPCommand.getCommand(command), arg); - } - - /** - * Returns a socket of the data connection. - * Wrapped as an {@link SSLSocket}, which carries out handshake processing. - * - * @param command The textual representation of the FTP command to send. - * @param arg The arguments to the FTP command. - * If this parameter is set to null, then the command is sent with - * no arguments. - * @return corresponding to the established data connection. - * Null is returned if an FTP protocol error is reported at any point - * during the establishment and initialization of the connection. - * @throws IOException If there is any problem with the connection. - * @see FTPClient#_openDataConnection_(int, String) - * @since 3.2 - */ - @Override protected Socket _openDataConnection_(String command, String arg) throws IOException { - Socket socket = super._openDataConnection_(command, arg); - _prepareDataSocket_(socket); - if (socket instanceof SSLSocket) { - SSLSocket sslSocket = (SSLSocket) socket; - - sslSocket.setUseClientMode(isClientMode); - sslSocket.setEnableSessionCreation(isCreation); - - // server mode - if (!isClientMode) { - sslSocket.setNeedClientAuth(isNeedClientAuth); - sslSocket.setWantClientAuth(isWantClientAuth); - } - if (suites != null) { - sslSocket.setEnabledCipherSuites(suites); - } - if (protocols != null) { - sslSocket.setEnabledProtocols(protocols); - } - sslSocket.startHandshake(); - } - - return socket; - } - - /** - * Performs any custom initialization for a newly created SSLSocket (before - * the SSL handshake happens). - * Called by {@link #_openDataConnection_(int, String)} immediately - * after creating the socket. - * The default implementation is a no-op - * - * @param socket the socket to set up - * @throws IOException on error - * @since 3.1 - */ - protected void _prepareDataSocket_(Socket socket) throws IOException { - } - - /** - * Get the currently configured {@link TrustManager}. - * - * @return A TrustManager instance. - */ - public TrustManager getTrustManager() { - return trustManager; - } - - /** - * Override the default {@link TrustManager} to use; if set to {@code null}, - * the default TrustManager from the JVM will be used. - * - * @param trustManager The TrustManager implementation to set, may be {@code null} - * @see TrustManagerUtils - */ - public void setTrustManager(TrustManager trustManager) { - this.trustManager = trustManager; - } - - /** - * Get the currently configured {@link HostnameVerifier}. - * The verifier is only used on client mode connections. - * - * @return A HostnameVerifier instance. - * @since 3.4 - */ - public HostnameVerifier getHostnameVerifier() { - return hostnameVerifier; - } - - /** - * Override the default {@link HostnameVerifier} to use. - * The verifier is only used on client mode connections. - * - * @param newHostnameVerifier The HostnameVerifier implementation to set or null to - * disable. - * @since 3.4 - */ - public void setHostnameVerifier(HostnameVerifier newHostnameVerifier) { - hostnameVerifier = newHostnameVerifier; - } - - /** - * Return whether or not endpoint identification using the HTTPS algorithm - * on Java 1.7+ is enabled. The default behaviour is for this to be disabled. - * - * This check is only performed on client mode connections. - * - * @return True if enabled, false if not. - * @since 3.4 - */ - public boolean isEndpointCheckingEnabled() { - return tlsEndpointChecking; - } - - /** - * Automatic endpoint identification checking using the HTTPS algorithm - * is supported on Java 1.7+. The default behaviour is for this to be disabled. - * - * This check is only performed on client mode connections. - * - * @param enable Enable automatic endpoint identification checking using the HTTPS algorithm on - * Java 1.7+. - * @since 3.4 - */ - public void setEndpointCheckingEnabled(boolean enable) { - tlsEndpointChecking = enable; - } - - /** - * Closes the connection to the FTP server and restores - * connection parameters to the default values. - *

- * Calls {@code setSocketFactory(null)} and {@code setServerSocketFactory(null)} - * to reset the factories that may have been changed during the session, - * e.g. by {@link #execPROT(String)} - * - * @throws IOException If an error occurs while disconnecting. - * @since 3.0 - */ - @Override public void disconnect() throws IOException { - super.disconnect(); - if (plainSocket != null) { - plainSocket.close(); - } - setSocketFactory(null); - setServerSocketFactory(null); - } - - /** - * Send the AUTH command with the specified mechanism. - * - * @param mechanism The mechanism name to send with the command. - * @return server reply. - * @throws IOException If an I/O error occurs while sending - * the command. - * @since 3.0 - */ - public int execAUTH(String mechanism) throws IOException { - return sendCommand(CMD_AUTH, mechanism); - } - - /** - * Send the ADAT command with the specified authentication data. - * - * @param data The data to send with the command. - * @return server reply. - * @throws IOException If an I/O error occurs while sending - * the command. - * @since 3.0 - */ - public int execADAT(byte[] data) throws IOException { - if (data != null) { - return sendCommand(CMD_ADAT, Base64.encodeBase64StringUnChunked(data)); - } else { - return sendCommand(CMD_ADAT); - } - } - - /** - * Send the CCC command to the server. - * The CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be - * assigned - * to a plain {@link Socket} instances - * - * @return server reply. - * @throws IOException If an I/O error occurs while sending - * the command. - * @since 3.0 - */ - public int execCCC() throws IOException { - int repCode = sendCommand(CMD_CCC); - // This will be performed by sendCommand(String, String) - // if (FTPReply.isPositiveCompletion(repCode)) { - // _socket_.close(); - // _socket_ = plainSocket; - // _controlInput_ = new BufferedReader( - // new InputStreamReader( - // _socket_.getInputStream(), getControlEncoding())); - // _controlOutput_ = new BufferedWriter( - // new OutputStreamWriter( - // _socket_.getOutputStream(), getControlEncoding())); - // } - return repCode; - } - - /** - * Send the MIC command with the specified data. - * - * @param data The data to send with the command. - * @return server reply. - * @throws IOException If an I/O error occurs while sending - * the command. - * @since 3.0 - */ - public int execMIC(byte[] data) throws IOException { - if (data != null) { - return sendCommand(CMD_MIC, Base64.encodeBase64StringUnChunked(data)); - } else { - return sendCommand(CMD_MIC, ""); // perhaps "=" or just sendCommand(String)? - } - } - - /** - * Send the CONF command with the specified data. - * - * @param data The data to send with the command. - * @return server reply. - * @throws IOException If an I/O error occurs while sending - * the command. - * @since 3.0 - */ - public int execCONF(byte[] data) throws IOException { - if (data != null) { - return sendCommand(CMD_CONF, Base64.encodeBase64StringUnChunked(data)); - } else { - return sendCommand(CMD_CONF, ""); // perhaps "=" or just sendCommand(String)? - } - } - - /** - * Send the ENC command with the specified data. - * - * @param data The data to send with the command. - * @return server reply. - * @throws IOException If an I/O error occurs while sending - * the command. - * @since 3.0 - */ - public int execENC(byte[] data) throws IOException { - if (data != null) { - return sendCommand(CMD_ENC, Base64.encodeBase64StringUnChunked(data)); - } else { - return sendCommand(CMD_ENC, ""); // perhaps "=" or just sendCommand(String)? - } - } - - /** - * Parses the given ADAT response line and base64-decodes the data. - * - * @param reply The ADAT reply to parse. - * @return the data in the reply, base64-decoded. - * @since 3.0 - */ - public byte[] parseADATReply(String reply) { - if (reply == null) { - return null; - } else { - return Base64.decodeBase64(extractPrefixedData("ADAT=", reply)); - } - } - - /** - * Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234 - * - * @param prefix the prefix to find - * @param reply where to find the prefix - * @return the remainder of the string after the prefix, or null if the prefix was not present. - */ - private String extractPrefixedData(String prefix, String reply) { - int idx = reply.indexOf(prefix); - if (idx == -1) { - return null; - } - // N.B. Cannot use trim before substring as leading space would affect the offset. - return reply.substring(idx + prefix.length()).trim(); - } - - // DEPRECATED - for API compatibility only - DO NOT USE - - /** @deprecated - not used - may be removed in a future release */ - @Deprecated public static String KEYSTORE_ALGORITHM; - - /** @deprecated - not used - may be removed in a future release */ - @Deprecated public static String TRUSTSTORE_ALGORITHM; - - /** @deprecated - not used - may be removed in a future release */ - @Deprecated public static String PROVIDER; - - /** @deprecated - not used - may be removed in a future release */ - @Deprecated public static String STORE_TYPE; -} -/* kate: indent-width 4; replace-tabs on; */ diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPSCommand.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPSCommand.java deleted file mode 100644 index 5937638b..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPSCommand.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -/** - * FTPS-specific commands. - * - * @since 2.0 - * @deprecated 3.0 DO NOT USE - */ -@Deprecated public final class FTPSCommand { - public static final int AUTH = 0; - public static final int ADAT = 1; - public static final int PBSZ = 2; - public static final int PROT = 3; - public static final int CCC = 4; - - public static final int AUTHENTICATION_SECURITY_MECHANISM = AUTH; - public static final int AUTHENTICATION_SECURITY_DATA = ADAT; - public static final int PROTECTION_BUFFER_SIZE = PBSZ; - public static final int DATA_CHANNEL_PROTECTION_LEVEL = PROT; - public static final int CLEAR_COMMAND_CHANNEL = CCC; - - private static final String[] _commands = { "AUTH", "ADAT", "PBSZ", "PROT", "CCC" }; - - /** - * Retrieve the FTPS command string corresponding to a specified - * command code. - * - * @param command The command code. - * @return The FTPS command string corresponding to a specified - * command code. - */ - public static final String getCommand(int command) { - return _commands[command]; - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPSServerSocketFactory.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPSServerSocketFactory.java deleted file mode 100644 index 168067bc..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPSServerSocketFactory.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.ServerSocket; - -import javax.net.ServerSocketFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLServerSocket; - -/** - * Server socket factory for FTPS connections. - * - * @since 2.2 - */ -public class FTPSServerSocketFactory extends ServerSocketFactory { - - /** Factory for secure socket factories */ - private final SSLContext context; - - public FTPSServerSocketFactory(SSLContext context) { - this.context = context; - } - - // Override the default superclass method - @Override public ServerSocket createServerSocket() throws IOException { - return init(this.context.getServerSocketFactory().createServerSocket()); - } - - @Override public ServerSocket createServerSocket(int port) throws IOException { - return init(this.context.getServerSocketFactory().createServerSocket(port)); - } - - @Override public ServerSocket createServerSocket(int port, int backlog) throws IOException { - return init(this.context.getServerSocketFactory().createServerSocket(port, backlog)); - } - - @Override public ServerSocket createServerSocket(int port, int backlog, InetAddress ifAddress) - throws IOException { - return init(this.context.getServerSocketFactory().createServerSocket(port, backlog, ifAddress)); - } - - /** - * Sets the socket so newly accepted connections will use SSL client mode. - * - * @param socket the SSLServerSocket to initialise - * @return the socket - * @throws ClassCastException if socket is not an instance of SSLServerSocket - */ - public ServerSocket init(ServerSocket socket) { - ((SSLServerSocket) socket).setUseClientMode(true); - return socket; - } -} - diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPSSocketFactory.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPSSocketFactory.java deleted file mode 100644 index 7bbf818c..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPSSocketFactory.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; -import java.net.UnknownHostException; - -import javax.net.SocketFactory; -import javax.net.ssl.SSLContext; - -/** - * Implementation of org.apache.commons.net.SocketFactory - * - * @since 2.0 - */ -public class FTPSSocketFactory extends SocketFactory { - - private final SSLContext context; - - public FTPSSocketFactory(SSLContext context) { - this.context = context; - } - - // Override the default implementation - @Override public Socket createSocket() throws IOException { - return this.context.getSocketFactory().createSocket(); - } - - @Override public Socket createSocket(String address, int port) - throws UnknownHostException, IOException { - return this.context.getSocketFactory().createSocket(address, port); - } - - @Override public Socket createSocket(InetAddress address, int port) throws IOException { - return this.context.getSocketFactory().createSocket(address, port); - } - - @Override - public Socket createSocket(String address, int port, InetAddress localAddress, int localPort) - throws UnknownHostException, IOException { - return this.context.getSocketFactory().createSocket(address, port, localAddress, localPort); - } - - @Override - public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) - throws IOException { - return this.context.getSocketFactory().createSocket(address, port, localAddress, localPort); - } - - // DEPRECATED METHODS - for API compatibility only - DO NOT USE - - /** - * @param port the port - * @return the socket - * @throws IOException on error - * @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int) instead} - */ - @Deprecated public java.net.ServerSocket createServerSocket(int port) throws IOException { - return this.init(this.context.getServerSocketFactory().createServerSocket(port)); - } - - /** - * @param port the port - * @param backlog the backlog - * @return the socket - * @throws IOException on error - * @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int, int) instead} - */ - @Deprecated public java.net.ServerSocket createServerSocket(int port, int backlog) - throws IOException { - return this.init(this.context.getServerSocketFactory().createServerSocket(port, backlog)); - } - - /** - * @param port the port - * @param backlog the backlog - * @param ifAddress the interface - * @return the socket - * @throws IOException on error - * @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int, int, InetAddress) - * instead} - */ - @Deprecated public java.net.ServerSocket createServerSocket(int port, int backlog, - InetAddress ifAddress) throws IOException { - return this.init( - this.context.getServerSocketFactory().createServerSocket(port, backlog, ifAddress)); - } - - /** - * @param socket the socket - * @return the socket - * @throws IOException on error - * @deprecated (2.2) use {@link FTPSServerSocketFactory#init(java.net.ServerSocket)} - */ - @Deprecated public java.net.ServerSocket init(java.net.ServerSocket socket) throws IOException { - ((javax.net.ssl.SSLServerSocket) socket).setUseClientMode(true); - return socket; - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPSTrustManager.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPSTrustManager.java deleted file mode 100644 index 0923ac02..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/FTPSTrustManager.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp; - -import aria.apache.commons.net.util.TrustManagerUtils; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -import javax.net.ssl.X509TrustManager; - -/** - * Do not use. - * - * @since 2.0 - * @deprecated 3.0 use - * {@link TrustManagerUtils#getValidateServerCertificateTrustManager() - * TrustManagerUtils#getValidateServerCertificateTrustManager()} instead - */ -@Deprecated public class FTPSTrustManager implements X509TrustManager { - private static final X509Certificate[] EMPTY_X509CERTIFICATE_ARRAY = new X509Certificate[] {}; - - /** - * No-op - */ - @Override public void checkClientTrusted(X509Certificate[] certificates, String authType) { - return; - } - - @Override public void checkServerTrusted(X509Certificate[] certificates, String authType) - throws CertificateException { - for (X509Certificate certificate : certificates) { - certificate.checkValidity(); - } - } - - @Override public X509Certificate[] getAcceptedIssuers() { - return EMPTY_X509CERTIFICATE_ARRAY; - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/OnFtpInputStreamListener.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/OnFtpInputStreamListener.java deleted file mode 100644 index f7adaf6d..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/OnFtpInputStreamListener.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) - * - * 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 aria.apache.commons.net.ftp; - -import aria.apache.commons.net.io.CopyStreamListener; - -/** - * Created by AriaL on 2017/9/26. - * ftp 上传文件流事件监听 - */ -public interface OnFtpInputStreamListener { - /** - * {@link CopyStreamListener#bytesTransferred(long, int, long)} - * - * @param totalBytesTransferred 已经上传的文件长度 - * @param bytesTransferred 上传byte长度 - */ - void onFtpInputStream(FTPClient client, long totalBytesTransferred, int bytesTransferred, - long streamSize); -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/package-info.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/package-info.java deleted file mode 100644 index f7df7cf0..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -/** - * FTP and FTPS support classes - */ -package aria.apache.commons.net.ftp; \ No newline at end of file diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/CompositeFileEntryParser.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/CompositeFileEntryParser.java deleted file mode 100644 index 638f67fb..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/CompositeFileEntryParser.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -import aria.apache.commons.net.ftp.FTPFile; -import aria.apache.commons.net.ftp.FTPFileEntryParser; -import aria.apache.commons.net.ftp.FTPFileEntryParserImpl; - -/** - * This implementation allows to pack some FileEntryParsers together - * and handle the case where to returned dirstyle isnt clearly defined. - * The matching parser will be cached. - * If the cached parser wont match due to the server changed the dirstyle, - * a new matching parser will be searched. - */ -public class CompositeFileEntryParser extends FTPFileEntryParserImpl { - private final FTPFileEntryParser[] ftpFileEntryParsers; - private FTPFileEntryParser cachedFtpFileEntryParser; - - public CompositeFileEntryParser(FTPFileEntryParser[] ftpFileEntryParsers) { - super(); - - this.cachedFtpFileEntryParser = null; - this.ftpFileEntryParsers = ftpFileEntryParsers; - } - - @Override public FTPFile parseFTPEntry(String listEntry) { - if (cachedFtpFileEntryParser != null) { - FTPFile matched = cachedFtpFileEntryParser.parseFTPEntry(listEntry); - if (matched != null) { - return matched; - } - } else { - for (FTPFileEntryParser ftpFileEntryParser : ftpFileEntryParsers) { - FTPFile matched = ftpFileEntryParser.parseFTPEntry(listEntry); - if (matched != null) { - cachedFtpFileEntryParser = ftpFileEntryParser; - return matched; - } - } - } - return null; - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java deleted file mode 100644 index 1d8988b6..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -import aria.apache.commons.net.ftp.Configurable; -import aria.apache.commons.net.ftp.FTPClientConfig; -import java.text.ParseException; -import java.util.Calendar; - -/** - *

- * This abstract class implements the common timestamp parsing - * algorithm for all the concrete parsers. Classes derived from - * this one will parse file listings via a supplied regular expression - * that pulls out the date portion as a separate string which is - * passed to the underlying {@link FTPTimestampParser delegate} to - * handle parsing of the file timestamp. - *

- * This class also implements the {@link Configurable Configurable} - * interface to allow the parser to be configured from the outside. - * - * @since 1.4 - */ -public abstract class ConfigurableFTPFileEntryParserImpl extends RegexFTPFileEntryParserImpl - implements Configurable { - - private final FTPTimestampParser timestampParser; - - /** - * constructor for this abstract class. - * - * @param regex Regular expression used main parsing of the - * file listing. - */ - public ConfigurableFTPFileEntryParserImpl(String regex) { - super(regex); - this.timestampParser = new FTPTimestampParserImpl(); - } - - /** - * constructor for this abstract class. - * - * @param regex Regular expression used main parsing of the - * file listing. - * @param flags the flags to apply, see - * {@link java.util.regex.Pattern#compile(String, int) Pattern#compile(String, int)}. Use 0 for - * none. - * @since 3.4 - */ - public ConfigurableFTPFileEntryParserImpl(String regex, int flags) { - super(regex, flags); - this.timestampParser = new FTPTimestampParserImpl(); - } - - /** - * This method is called by the concrete parsers to delegate - * timestamp parsing to the timestamp parser. - * - * @param timestampStr the timestamp string pulled from the - * file listing by the regular expression parser, to be submitted - * to the timestampParser for extracting the timestamp. - * @return a java.util.Calendar containing results of the - * timestamp parse. - * @throws ParseException on parse error - */ - public Calendar parseTimestamp(String timestampStr) throws ParseException { - return this.timestampParser.parseTimestamp(timestampStr); - } - - /** - * Implementation of the {@link Configurable Configurable} - * interface. Configures this parser by delegating to the - * underlying Configurable FTPTimestampParser implementation, ' - * passing it the supplied {@link FTPClientConfig FTPClientConfig} - * if that is non-null or a default configuration defined by - * each concrete subclass. - * - * @param config the configuration to be used to configure this parser. - * If it is null, a default configuration defined by - * each concrete subclass is used instead. - */ - @Override public void configure(FTPClientConfig config) { - if (this.timestampParser instanceof Configurable) { - FTPClientConfig defaultCfg = getDefaultConfiguration(); - if (config != null) { - if (null == config.getDefaultDateFormatStr()) { - config.setDefaultDateFormatStr(defaultCfg.getDefaultDateFormatStr()); - } - if (null == config.getRecentDateFormatStr()) { - config.setRecentDateFormatStr(defaultCfg.getRecentDateFormatStr()); - } - ((Configurable) this.timestampParser).configure(config); - } else { - ((Configurable) this.timestampParser).configure(defaultCfg); - } - } - } - - /** - * Each concrete subclass must define this member to create - * a default configuration to be used when that subclass is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * - * @return the default configuration for the subclass. - */ - protected abstract FTPClientConfig getDefaultConfiguration(); -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java deleted file mode 100644 index cc499c71..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -import aria.apache.commons.net.ftp.Configurable; -import aria.apache.commons.net.ftp.FTPClient; -import aria.apache.commons.net.ftp.FTPClientConfig; -import aria.apache.commons.net.ftp.FTPFileEntryParser; -import java.util.regex.Pattern; - -/** - * This is the default implementation of the - * FTPFileEntryParserFactory interface. This is the - * implementation that will be used by - * FTPClient.listFiles() - * if no other implementation has been specified. - * - * @see FTPClient#listFiles - * @see FTPClient#setParserFactory - */ -public class DefaultFTPFileEntryParserFactory implements FTPFileEntryParserFactory { - - // Match a plain Java Identifier - private static final String JAVA_IDENTIFIER = - "\\p{javaJavaIdentifierStart}(\\p{javaJavaIdentifierPart})*"; - // Match a qualified name, e.g. a.b.c.Name - but don't allow the default package as that would allow "VMS"/"UNIX" etc. - private static final String JAVA_QUALIFIED_NAME = - "(" + JAVA_IDENTIFIER + "\\.)+" + JAVA_IDENTIFIER; - // Create the pattern, as it will be reused many times - private static final Pattern JAVA_QUALIFIED_NAME_PATTERN = Pattern.compile(JAVA_QUALIFIED_NAME); - - /** - * This default implementation of the FTPFileEntryParserFactory - * interface works according to the following logic: - * First it attempts to interpret the supplied key as a fully - * qualified classname (default package is not allowed) of a class implementing the - * FTPFileEntryParser interface. If that succeeds, a parser - * object of this class is instantiated and is returned; - * otherwise it attempts to interpret the key as an identirier - * commonly used by the FTP SYST command to identify systems. - *

- * If key is not recognized as a fully qualified - * classname known to the system, this method will then attempt - * to see whether it contains a string identifying one of - * the known parsers. This comparison is case-insensitive. - * The intent here is where possible, to select as keys strings - * which are returned by the SYST command on the systems which - * the corresponding parser successfully parses. This enables - * this factory to be used in the auto-detection system. - * - * @param key should be a fully qualified classname corresponding to - * a class implementing the FTPFileEntryParser interface
- * OR
- * a string containing (case-insensitively) one of the - * following keywords: - *

    - *
  • {@link FTPClientConfig#SYST_UNIX UNIX}
  • - *
  • {@link FTPClientConfig#SYST_NT WINDOWS}
  • - *
  • {@link FTPClientConfig#SYST_OS2 OS/2}
  • - *
  • {@link FTPClientConfig#SYST_OS400 OS/400}
  • - *
  • {@link FTPClientConfig#SYST_AS400 AS/400}
  • - *
  • {@link FTPClientConfig#SYST_VMS VMS}
  • - *
  • {@link FTPClientConfig#SYST_MVS MVS}
  • - *
  • {@link FTPClientConfig#SYST_NETWARE NETWARE}
  • - *
  • {@link FTPClientConfig#SYST_L8 TYPE:L8}
  • - *
- * @return the FTPFileEntryParser corresponding to the supplied key. - * @throws ParserInitializationException thrown if for any reason the factory cannot resolve - * the supplied key into an FTPFileEntryParser. - * @see FTPFileEntryParser - */ - @Override public FTPFileEntryParser createFileEntryParser(String key) { - if (key == null) { - throw new ParserInitializationException("Parser key cannot be null"); - } - return createFileEntryParser(key, null); - } - - // Common method to process both key and config parameters. - private FTPFileEntryParser createFileEntryParser(String key, FTPClientConfig config) { - FTPFileEntryParser parser = null; - - // Is the key a possible class name? - if (JAVA_QUALIFIED_NAME_PATTERN.matcher(key).matches()) { - try { - Class parserClass = Class.forName(key); - try { - parser = (FTPFileEntryParser) parserClass.newInstance(); - } catch (ClassCastException e) { - throw new ParserInitializationException(parserClass.getName() - + " does not implement the interface " - + "FTPFileEntryParser.", e); - } catch (Exception e) { - throw new ParserInitializationException("Error initializing parser", e); - } catch (ExceptionInInitializerError e) { - throw new ParserInitializationException("Error initializing parser", e); - } - } catch (ClassNotFoundException e) { - // OK, assume it is an alias - } - } - - if (parser == null) { // Now try for aliases - String ukey = key.toUpperCase(java.util.Locale.ENGLISH); - if (ukey.indexOf(FTPClientConfig.SYST_UNIX_TRIM_LEADING) >= 0) { - parser = new UnixFTPEntryParser(config, true); - } - // must check this after SYST_UNIX_TRIM_LEADING as it is a substring of it - else if (ukey.indexOf(FTPClientConfig.SYST_UNIX) >= 0) { - parser = new UnixFTPEntryParser(config, false); - } else if (ukey.indexOf(FTPClientConfig.SYST_VMS) >= 0) { - parser = new VMSVersioningFTPEntryParser(config); - } else if (ukey.indexOf(FTPClientConfig.SYST_NT) >= 0) { - parser = createNTFTPEntryParser(config); - } else if (ukey.indexOf(FTPClientConfig.SYST_OS2) >= 0) { - parser = new OS2FTPEntryParser(config); - } else if (ukey.indexOf(FTPClientConfig.SYST_OS400) >= 0 - || ukey.indexOf(FTPClientConfig.SYST_AS400) >= 0) { - parser = createOS400FTPEntryParser(config); - } else if (ukey.indexOf(FTPClientConfig.SYST_MVS) >= 0) { - parser = new MVSFTPEntryParser(); // Does not currently support config parameter - } else if (ukey.indexOf(FTPClientConfig.SYST_NETWARE) >= 0) { - parser = new NetwareFTPEntryParser(config); - } else if (ukey.indexOf(FTPClientConfig.SYST_MACOS_PETER) >= 0) { - parser = new MacOsPeterFTPEntryParser(config); - } else if (ukey.indexOf(FTPClientConfig.SYST_L8) >= 0) { - // L8 normally means Unix, but move it to the end for some L8 systems that aren't. - // This check should be last! - parser = new UnixFTPEntryParser(config); - } else { - throw new ParserInitializationException("Unknown parser type: " + key); - } - } - - if (parser instanceof Configurable) { - ((Configurable) parser).configure(config); - } - return parser; - } - - /** - *

Implementation extracts a key from the supplied - * {@link FTPClientConfig FTPClientConfig} - * parameter and creates an object implementing the - * interface FTPFileEntryParser and uses the supplied configuration - * to configure it. - *

- * Note that this method will generally not be called in scenarios - * that call for autodetection of parser type but rather, for situations - * where the user knows that the server uses a non-default configuration - * and knows what that configuration is. - *

- * - * @param config A {@link FTPClientConfig FTPClientConfig} - * used to configure the parser created - * @return the @link FTPFileEntryParser FTPFileEntryParser} so created. - * @throws ParserInitializationException Thrown on any exception in instantiation - * @throws NullPointerException if {@code config} is {@code null} - * @since 1.4 - */ - @Override public FTPFileEntryParser createFileEntryParser(FTPClientConfig config) - throws ParserInitializationException { - String key = config.getServerSystemKey(); - return createFileEntryParser(key, config); - } - - public FTPFileEntryParser createUnixFTPEntryParser() { - return new UnixFTPEntryParser(); - } - - public FTPFileEntryParser createVMSVersioningFTPEntryParser() { - return new VMSVersioningFTPEntryParser(); - } - - public FTPFileEntryParser createNetwareFTPEntryParser() { - return new NetwareFTPEntryParser(); - } - - public FTPFileEntryParser createNTFTPEntryParser() { - return createNTFTPEntryParser(null); - } - - /** - * Creates an NT FTP parser: if the config exists, and the system key equals - * {@link FTPClientConfig.SYST_NT} then a plain {@link NTFTPEntryParser} is used, - * otherwise a composite of {@link NTFTPEntryParser} and {@link UnixFTPEntryParser} is used. - * - * @param config the config to use, may be {@code null} - * @return the parser - */ - private FTPFileEntryParser createNTFTPEntryParser(FTPClientConfig config) { - if (config != null && FTPClientConfig.SYST_NT.equals(config.getServerSystemKey())) { - return new NTFTPEntryParser(config); - } else { - // clone the config as it may be changed by the parsers (NET-602) - final FTPClientConfig config2 = (config != null) ? new FTPClientConfig(config) : null; - return new CompositeFileEntryParser(new FTPFileEntryParser[] { - new NTFTPEntryParser(config), new UnixFTPEntryParser(config2, - config2 != null && FTPClientConfig.SYST_UNIX_TRIM_LEADING.equals( - config2.getServerSystemKey())) - }); - } - } - - public FTPFileEntryParser createOS2FTPEntryParser() { - return new OS2FTPEntryParser(); - } - - public FTPFileEntryParser createOS400FTPEntryParser() { - return createOS400FTPEntryParser(null); - } - - /** - * Creates an OS400 FTP parser: if the config exists, and the system key equals - * {@link FTPClientConfig.SYST_OS400} then a plain {@link OS400FTPEntryParser} is used, - * otherwise a composite of {@link OS400FTPEntryParser} and {@link UnixFTPEntryParser} is used. - * - * @param config the config to use, may be {@code null} - * @return the parser - */ - private FTPFileEntryParser createOS400FTPEntryParser(FTPClientConfig config) { - if (config != null && FTPClientConfig.SYST_OS400.equals(config.getServerSystemKey())) { - return new OS400FTPEntryParser(config); - } else { - // clone the config as it may be changed by the parsers (NET-602) - final FTPClientConfig config2 = (config != null) ? new FTPClientConfig(config) : null; - return new CompositeFileEntryParser(new FTPFileEntryParser[] { - new OS400FTPEntryParser(config), new UnixFTPEntryParser(config2, - config2 != null && FTPClientConfig.SYST_UNIX_TRIM_LEADING.equals( - config2.getServerSystemKey())) - }); - } - } - - public FTPFileEntryParser createMVSEntryParser() { - return new MVSFTPEntryParser(); - } -} - diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java deleted file mode 100644 index ca31583a..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -import aria.apache.commons.net.ftp.FTPFile; -import aria.apache.commons.net.ftp.FTPFileEntryParser; -import java.util.Calendar; - -/** - * Parser for the Connect Enterprise Unix FTP Server From Sterling Commerce. - * Here is a sample of the sort of output line this parser processes: - * "-C--E-----FTP B QUA1I1 18128 41 Aug 12 13:56 QUADTEST" - *

- * Note: EnterpriseUnixFTPEntryParser can only be instantiated through the - * DefaultFTPParserFactory by classname. It will not be chosen - * by the autodetection scheme. - * - * - * @version $Id: EnterpriseUnixFTPEntryParser.java 1741829 2016-05-01 00:24:44Z sebb $ - * @see FTPFileEntryParser FTPFileEntryParser (for usage instructions) - * @see DefaultFTPFileEntryParserFactory - */ -public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl { - - /** - * months abbreviations looked for by this parser. Also used - * to determine which month has been matched by the parser. - */ - private static final String MONTHS = "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"; - - /** - * this is the regular expression used by this parser. - */ - private static final String REGEX = - "(([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])" - + "([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z])([\\-]|[A-Z]))" - + "(\\S*)\\s*" - // 12 - + "(\\S+)\\s*" - // 13 - + "(\\S*)\\s*" - // 14 user - + "(\\d*)\\s*" - // 15 group - + "(\\d*)\\s*" - // 16 filesize - + MONTHS - // 17 month - + "\\s*" - // TODO should the space be optional? - // TODO \\d* should be \\d? surely ? Otherwise 01111 is allowed - + "((?:[012]\\d*)|(?:3[01]))\\s*" - // 18 date [012]\d* or 3[01] - + "((\\d\\d\\d\\d)|((?:[01]\\d)|(?:2[0123])):([012345]\\d))\\s" - // 20 \d\d\d\d = year OR - // 21 [01]\d or 2[0123] hour + ':' - // 22 [012345]\d = minute - + "(\\S*)(\\s*.*)"; // 23 name - - /** - * The sole constructor for a EnterpriseUnixFTPEntryParser object. - */ - public EnterpriseUnixFTPEntryParser() { - super(REGEX); - } - - /** - * Parses a line of a unix FTP server file listing and converts it into a - * usable format in the form of an FTPFile instance. If - * the file listing line doesn't describe a file, null is - * returned, otherwise a FTPFile instance representing the - * files in the directory is returned. - * - * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - @Override public FTPFile parseFTPEntry(String entry) { - - FTPFile file = new FTPFile(); - file.setRawListing(entry); - - if (matches(entry)) { - String usr = group(14); - String grp = group(15); - String filesize = group(16); - String mo = group(17); - String da = group(18); - String yr = group(20); - String hr = group(21); - String min = group(22); - String name = group(23); - - file.setType(FTPFile.FILE_TYPE); - file.setUser(usr); - file.setGroup(grp); - try { - file.setSize(Long.parseLong(filesize)); - } catch (NumberFormatException e) { - // intentionally do nothing - } - - Calendar cal = Calendar.getInstance(); - cal.set(Calendar.MILLISECOND, 0); - cal.set(Calendar.SECOND, 0); - cal.set(Calendar.MINUTE, 0); - cal.set(Calendar.HOUR_OF_DAY, 0); - - int pos = MONTHS.indexOf(mo); - int month = pos / 4; - final int missingUnit; // the first missing unit - try { - - if (yr != null) { - // it's a year; there are no hours and minutes - cal.set(Calendar.YEAR, Integer.parseInt(yr)); - missingUnit = Calendar.HOUR_OF_DAY; - } else { - // it must be hour/minute or we wouldn't have matched - missingUnit = Calendar.SECOND; - int year = cal.get(Calendar.YEAR); - - // if the month we're reading is greater than now, it must - // be last year - if (cal.get(Calendar.MONTH) < month) { - year--; - } - cal.set(Calendar.YEAR, year); - cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hr)); - cal.set(Calendar.MINUTE, Integer.parseInt(min)); - } - cal.set(Calendar.MONTH, month); - cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(da)); - cal.clear(missingUnit); - file.setTimestamp(cal); - } catch (NumberFormatException e) { - // do nothing, date will be uninitialized - } - file.setName(name); - - return file; - } - return null; - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java deleted file mode 100644 index 2e3c84e0..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -import aria.apache.commons.net.ftp.FTPClientConfig; -import aria.apache.commons.net.ftp.FTPFileEntryParser; - -/** - * The interface describes a factory for creating FTPFileEntryParsers. - * - * @since 1.2 - */ -public interface FTPFileEntryParserFactory { - /** - * Implementation should be a method that decodes the - * supplied key and creates an object implementing the - * interface FTPFileEntryParser. - * - * @param key A string that somehow identifies an - * FTPFileEntryParser to be created. - * @return the FTPFileEntryParser created. - * @throws ParserInitializationException Thrown on any exception in instantiation - */ - public FTPFileEntryParser createFileEntryParser(String key) throws ParserInitializationException; - - /** - *

- * Implementation should be a method that extracts - * a key from the supplied {@link FTPClientConfig FTPClientConfig} - * parameter and creates an object implementing the - * interface FTPFileEntryParser and uses the supplied configuration - * to configure it. - *

- * Note that this method will generally not be called in scenarios - * that call for autodetection of parser type but rather, for situations - * where the user knows that the server uses a non-default configuration - * and knows what that configuration is. - *

- * - * @param config A {@link FTPClientConfig FTPClientConfig} - * used to configure the parser created - * @return the @link FTPFileEntryParser FTPFileEntryParser} so created. - * @throws ParserInitializationException Thrown on any exception in instantiation - * @since 1.4 - */ - public FTPFileEntryParser createFileEntryParser(FTPClientConfig config) - throws ParserInitializationException; -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/FTPTimestampParser.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/FTPTimestampParser.java deleted file mode 100644 index dab122a4..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/FTPTimestampParser.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -import java.text.ParseException; -import java.util.Calendar; - -/** - * This interface specifies the concept of parsing an FTP server's - * timestamp. - * - * @since 1.4 - */ -public interface FTPTimestampParser { - - /** - * the default default date format. - */ - public static final String DEFAULT_SDF = UnixFTPEntryParser.DEFAULT_DATE_FORMAT; - /** - * the default recent date format. - */ - public static final String DEFAULT_RECENT_SDF = UnixFTPEntryParser.DEFAULT_RECENT_DATE_FORMAT; - - /** - * Parses the supplied datestamp parameter. This parameter typically would - * have been pulled from a longer FTP listing via the regular expression - * mechanism - * - * @param timestampStr - the timestamp portion of the FTP directory listing - * to be parsed - * @return a java.util.Calendar object initialized to the date - * parsed by the parser - * @throws ParseException if none of the parser mechanisms belonging to - * the implementor can parse the input. - */ - public Calendar parseTimestamp(String timestampStr) throws ParseException; -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java deleted file mode 100644 index e84209ff..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -import aria.apache.commons.net.ftp.Configurable; -import aria.apache.commons.net.ftp.FTPClientConfig; -import java.text.DateFormatSymbols; -import java.text.ParseException; -import java.text.ParsePosition; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.TimeZone; - -/** - * Default implementation of the {@link FTPTimestampParser FTPTimestampParser} - * interface also implements the {@link Configurable Configurable} - * interface to allow the parsing to be configured from the outside. - * - * @see ConfigurableFTPFileEntryParserImpl - * @since 1.4 - */ -public class FTPTimestampParserImpl implements FTPTimestampParser, Configurable { - - /** The date format for all dates, except possibly recent dates. Assumed to include the year. */ - private SimpleDateFormat defaultDateFormat; - /* The index in CALENDAR_UNITS of the smallest time unit in defaultDateFormat */ - private int defaultDateSmallestUnitIndex; - - /** The format used for recent dates (which don't have the year). May be null. */ - private SimpleDateFormat recentDateFormat; - /* The index in CALENDAR_UNITS of the smallest time unit in recentDateFormat */ - private int recentDateSmallestUnitIndex; - - private boolean lenientFutureDates = false; - - /* - * List of units in order of increasing significance. - * This allows the code to clear all units in the Calendar until it - * reaches the least significant unit in the parse string. - * The date formats are analysed to find the least significant - * unit (e.g. Minutes or Milliseconds) and the appropriate index to - * the array is saved. - * This is done by searching the array for the unit specifier, - * and returning the index. When clearing the Calendar units, - * the code loops through the array until the previous entry. - * e.g. for MINUTE it would clear MILLISECOND and SECOND - */ - private static final int[] CALENDAR_UNITS = { - Calendar.MILLISECOND, Calendar.SECOND, Calendar.MINUTE, Calendar.HOUR_OF_DAY, - Calendar.DAY_OF_MONTH, Calendar.MONTH, Calendar.YEAR - }; - - /* - * Return the index to the array representing the least significant - * unit found in the date format. - * Default is 0 (to avoid dropping precision) - */ - private static int getEntry(SimpleDateFormat dateFormat) { - if (dateFormat == null) { - return 0; - } - final String FORMAT_CHARS = "SsmHdM"; - final String pattern = dateFormat.toPattern(); - for (char ch : FORMAT_CHARS.toCharArray()) { - if (pattern.indexOf(ch) != -1) { // found the character - switch (ch) { - case 'S': - return indexOf(Calendar.MILLISECOND); - case 's': - return indexOf(Calendar.SECOND); - case 'm': - return indexOf(Calendar.MINUTE); - case 'H': - return indexOf(Calendar.HOUR_OF_DAY); - case 'd': - return indexOf(Calendar.DAY_OF_MONTH); - case 'M': - return indexOf(Calendar.MONTH); - } - } - } - return 0; - } - - /* - * Find the entry in the CALENDAR_UNITS array. - */ - private static int indexOf(int calendarUnit) { - int i; - for (i = 0; i < CALENDAR_UNITS.length; i++) { - if (calendarUnit == CALENDAR_UNITS[i]) { - return i; - } - } - return 0; - } - - /* - * Sets the Calendar precision (used by FTPFile#toFormattedDate) by clearing - * the immediately preceeding unit (if any). - * Unfortunately the clear(int) method results in setting all other units. - */ - private static void setPrecision(int index, Calendar working) { - if (index <= 0) { // e.g. MILLISECONDS - return; - } - final int field = CALENDAR_UNITS[index - 1]; - // Just in case the analysis is wrong, stop clearing if - // field value is not the default. - final int value = working.get(field); - if (value != 0) { // don't reset if it has a value - // new Throwable("Unexpected value "+value).printStackTrace(); // DEBUG - } else { - working.clear(field); // reset just the required field - } - } - - /** - * The only constructor for this class. - */ - public FTPTimestampParserImpl() { - setDefaultDateFormat(DEFAULT_SDF, null); - setRecentDateFormat(DEFAULT_RECENT_SDF, null); - } - - /** - * Implements the one {@link FTPTimestampParser#parseTimestamp(String) method} - * in the {@link FTPTimestampParser FTPTimestampParser} interface - * according to this algorithm: - * - * If the recentDateFormat member has been defined, try to parse the - * supplied string with that. If that parse fails, or if the recentDateFormat - * member has not been defined, attempt to parse with the defaultDateFormat - * member. If that fails, throw a ParseException. - * - * This method assumes that the server time is the same as the local time. - * - * @param timestampStr The timestamp to be parsed - * @return a Calendar with the parsed timestamp - * @see FTPTimestampParserImpl#parseTimestamp(String, Calendar) - */ - @Override public Calendar parseTimestamp(String timestampStr) throws ParseException { - Calendar now = Calendar.getInstance(); - return parseTimestamp(timestampStr, now); - } - - /** - * If the recentDateFormat member has been defined, try to parse the - * supplied string with that. If that parse fails, or if the recentDateFormat - * member has not been defined, attempt to parse with the defaultDateFormat - * member. If that fails, throw a ParseException. - * - * This method allows a {@link Calendar} instance to be passed in which represents the - * current (system) time. - * - * @param timestampStr The timestamp to be parsed - * @param serverTime The current time for the server - * @return the calendar - * @throws ParseException if timestamp cannot be parsed - * @see FTPTimestampParser#parseTimestamp(String) - * @since 1.5 - */ - public Calendar parseTimestamp(String timestampStr, Calendar serverTime) throws ParseException { - Calendar working = (Calendar) serverTime.clone(); - working.setTimeZone(getServerTimeZone()); // is this needed? - - Date parsed = null; - - if (recentDateFormat != null) { - Calendar now = (Calendar) serverTime.clone();// Copy this, because we may change it - now.setTimeZone(this.getServerTimeZone()); - if (lenientFutureDates) { - // add a day to "now" so that "slop" doesn't cause a date - // slightly in the future to roll back a full year. (Bug 35181 => NET-83) - now.add(Calendar.DAY_OF_MONTH, 1); - } - // The Java SimpleDateFormat class uses the epoch year 1970 if not present in the input - // As 1970 was not a leap year, it cannot parse "Feb 29" correctly. - // Java 1.5+ returns Mar 1 1970 - // Temporarily add the current year to the short date time - // to cope with short-date leap year strings. - // Since Feb 29 is more that 6 months from the end of the year, this should be OK for - // all instances of short dates which are +- 6 months from current date. - // TODO this won't always work for systems that use short dates +0/-12months - // e.g. if today is Jan 1 2001 and the short date is Feb 29 - String year = Integer.toString(now.get(Calendar.YEAR)); - String timeStampStrPlusYear = timestampStr + " " + year; - SimpleDateFormat hackFormatter = new SimpleDateFormat(recentDateFormat.toPattern() + " yyyy", - recentDateFormat.getDateFormatSymbols()); - hackFormatter.setLenient(false); - hackFormatter.setTimeZone(recentDateFormat.getTimeZone()); - ParsePosition pp = new ParsePosition(0); - parsed = hackFormatter.parse(timeStampStrPlusYear, pp); - // Check if we parsed the full string, if so it must have been a short date originally - if (parsed != null && pp.getIndex() == timeStampStrPlusYear.length()) { - working.setTime(parsed); - if (working.after(now)) { // must have been last year instead - working.add(Calendar.YEAR, -1); - } - setPrecision(recentDateSmallestUnitIndex, working); - return working; - } - } - - ParsePosition pp = new ParsePosition(0); - parsed = defaultDateFormat.parse(timestampStr, pp); - // note, length checks are mandatory for us since - // SimpleDateFormat methods will succeed if less than - // full string is matched. They will also accept, - // despite "leniency" setting, a two-digit number as - // a valid year (e.g. 22:04 will parse as 22 A.D.) - // so could mistakenly confuse an hour with a year, - // if we don't insist on full length parsing. - if (parsed != null && pp.getIndex() == timestampStr.length()) { - working.setTime(parsed); - } else { - throw new ParseException("Timestamp '" - + timestampStr - + "' could not be parsed using a server time of " - + serverTime.getTime().toString(), pp.getErrorIndex()); - } - setPrecision(defaultDateSmallestUnitIndex, working); - return working; - } - - /** - * @return Returns the defaultDateFormat. - */ - public SimpleDateFormat getDefaultDateFormat() { - return defaultDateFormat; - } - - /** - * @return Returns the defaultDateFormat pattern string. - */ - public String getDefaultDateFormatString() { - return defaultDateFormat.toPattern(); - } - - /** - * @param format The defaultDateFormat to be set. - * @param dfs the symbols to use (may be null) - */ - private void setDefaultDateFormat(String format, DateFormatSymbols dfs) { - if (format != null) { - if (dfs != null) { - this.defaultDateFormat = new SimpleDateFormat(format, dfs); - } else { - this.defaultDateFormat = new SimpleDateFormat(format); - } - this.defaultDateFormat.setLenient(false); - } else { - this.defaultDateFormat = null; - } - this.defaultDateSmallestUnitIndex = getEntry(this.defaultDateFormat); - } - - /** - * @return Returns the recentDateFormat. - */ - public SimpleDateFormat getRecentDateFormat() { - return recentDateFormat; - } - - /** - * @return Returns the recentDateFormat. - */ - public String getRecentDateFormatString() { - return recentDateFormat.toPattern(); - } - - /** - * @param format The recentDateFormat to set. - * @param dfs the symbols to use (may be null) - */ - private void setRecentDateFormat(String format, DateFormatSymbols dfs) { - if (format != null) { - if (dfs != null) { - this.recentDateFormat = new SimpleDateFormat(format, dfs); - } else { - this.recentDateFormat = new SimpleDateFormat(format); - } - this.recentDateFormat.setLenient(false); - } else { - this.recentDateFormat = null; - } - this.recentDateSmallestUnitIndex = getEntry(this.recentDateFormat); - } - - /** - * @return returns an array of 12 strings representing the short - * month names used by this parse. - */ - public String[] getShortMonths() { - return defaultDateFormat.getDateFormatSymbols().getShortMonths(); - } - - /** - * @return Returns the serverTimeZone used by this parser. - */ - public TimeZone getServerTimeZone() { - return this.defaultDateFormat.getTimeZone(); - } - - /** - * sets a TimeZone represented by the supplied ID string into all - * of the parsers used by this server. - * - * @param serverTimeZone Time Id java.util.TimeZone id used by - * the ftp server. If null the client's local time zone is assumed. - */ - private void setServerTimeZone(String serverTimeZoneId) { - TimeZone serverTimeZone = TimeZone.getDefault(); - if (serverTimeZoneId != null) { - serverTimeZone = TimeZone.getTimeZone(serverTimeZoneId); - } - this.defaultDateFormat.setTimeZone(serverTimeZone); - if (this.recentDateFormat != null) { - this.recentDateFormat.setTimeZone(serverTimeZone); - } - } - - /** - * Implementation of the {@link Configurable Configurable} - * interface. Configures this FTPTimestampParser according - * to the following logic: - *

- * Set up the {@link FTPClientConfig#setDefaultDateFormatStr(String) defaultDateFormat} - * and optionally the {@link FTPClientConfig#setRecentDateFormatStr(String) recentDateFormat} - * to values supplied in the config based on month names configured as follows: - *

- *
    - *
  • If a {@link FTPClientConfig#setShortMonthNames(String) shortMonthString} - * has been supplied in the config, use that to parse parse timestamps.
  • - *
  • Otherwise, if a {@link FTPClientConfig#setServerLanguageCode(String) serverLanguageCode} - * has been supplied in the config, use the month names represented - * by that {@link FTPClientConfig#lookupDateFormatSymbols(String) language} - * to parse timestamps.
  • - *
  • otherwise use default English month names
  • - *

- * Finally if a {@link FTPClientConfig#setServerTimeZoneId(String) - * serverTimeZoneId} - * has been supplied via the config, set that into all date formats that have - * been configured. - *

- */ - @Override public void configure(FTPClientConfig config) { - DateFormatSymbols dfs = null; - - String languageCode = config.getServerLanguageCode(); - String shortmonths = config.getShortMonthNames(); - if (shortmonths != null) { - dfs = FTPClientConfig.getDateFormatSymbols(shortmonths); - } else if (languageCode != null) { - dfs = FTPClientConfig.lookupDateFormatSymbols(languageCode); - } else { - dfs = FTPClientConfig.lookupDateFormatSymbols("en"); - } - - String recentFormatString = config.getRecentDateFormatStr(); - setRecentDateFormat(recentFormatString, dfs); - - String defaultFormatString = config.getDefaultDateFormatStr(); - if (defaultFormatString == null) { - throw new IllegalArgumentException("defaultFormatString cannot be null"); - } - setDefaultDateFormat(defaultFormatString, dfs); - - setServerTimeZone(config.getServerTimeZoneId()); - - this.lenientFutureDates = config.isLenientFutureDates(); - } - - /** - * @return Returns the lenientFutureDates. - */ - boolean isLenientFutureDates() { - return lenientFutureDates; - } - - /** - * @param lenientFutureDates The lenientFutureDates to set. - */ - void setLenientFutureDates(boolean lenientFutureDates) { - this.lenientFutureDates = lenientFutureDates; - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/MLSxEntryParser.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/MLSxEntryParser.java deleted file mode 100644 index b6d11bb8..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/MLSxEntryParser.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -import aria.apache.commons.net.ftp.FTPFile; -import aria.apache.commons.net.ftp.FTPFileEntryParserImpl; -import java.text.ParsePosition; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.Locale; -import java.util.TimeZone; - -/** - * Parser class for MSLT and MLSD replies. See RFC 3659. - *

- * Format is as follows: - *

- * entry            = [ facts ] SP pathname
- * facts            = 1*( fact ";" )
- * fact             = factname "=" value
- * factname         = "Size" / "Modify" / "Create" /
- *                    "Type" / "Unique" / "Perm" /
- *                    "Lang" / "Media-Type" / "CharSet" /
- * os-depend-fact / local-fact
- * os-depend-fact   = {IANA assigned OS name} "." token
- * local-fact       = "X." token
- * value            = *SCHAR
- *
- * Sample os-depend-fact:
- * UNIX.group=0;UNIX.mode=0755;UNIX.owner=0;
- * 
- * A single control response entry (MLST) is returned with a leading space; - * multiple (data) entries are returned without any leading spaces. - * The parser requires that the leading space from the MLST entry is removed. - * MLSD entries can begin with a single space if there are no facts. - * - * @since 3.0 - */ -public class MLSxEntryParser extends FTPFileEntryParserImpl { - // This class is immutable, so a single instance can be shared. - private static final MLSxEntryParser PARSER = new MLSxEntryParser(); - - private static final HashMap TYPE_TO_INT = new HashMap(); - - static { - TYPE_TO_INT.put("file", Integer.valueOf(FTPFile.FILE_TYPE)); - TYPE_TO_INT.put("cdir", Integer.valueOf(FTPFile.DIRECTORY_TYPE)); // listed directory - TYPE_TO_INT.put("pdir", Integer.valueOf(FTPFile.DIRECTORY_TYPE)); // a parent dir - TYPE_TO_INT.put("dir", Integer.valueOf(FTPFile.DIRECTORY_TYPE)); // dir or sub-dir - } - - private static int UNIX_GROUPS[] = { // Groups in order of mode digits - FTPFile.USER_ACCESS, FTPFile.GROUP_ACCESS, FTPFile.WORLD_ACCESS, - }; - - private static int UNIX_PERMS[][] = { // perm bits, broken down by octal int value -/* 0 */ {}, -/* 1 */ { FTPFile.EXECUTE_PERMISSION }, -/* 2 */ { FTPFile.WRITE_PERMISSION }, -/* 3 */ { FTPFile.EXECUTE_PERMISSION, FTPFile.WRITE_PERMISSION }, -/* 4 */ { FTPFile.READ_PERMISSION }, -/* 5 */ { FTPFile.READ_PERMISSION, FTPFile.EXECUTE_PERMISSION }, -/* 6 */ { FTPFile.READ_PERMISSION, FTPFile.WRITE_PERMISSION }, -/* 7 */ { FTPFile.READ_PERMISSION, FTPFile.WRITE_PERMISSION, FTPFile.EXECUTE_PERMISSION }, - }; - - /** - * Create the parser for MSLT and MSLD listing entries - * This class is immutable, so one can use {@link #getInstance()} instead. - */ - public MLSxEntryParser() { - super(); - } - - @Override public FTPFile parseFTPEntry(String entry) { - if (entry.startsWith(" ")) {// leading space means no facts are present - if (entry.length() > 1) { // is there a path name? - FTPFile file = new FTPFile(); - file.setRawListing(entry); - file.setName(entry.substring(1)); - return file; - } else { - return null; // Invalid - no pathname - } - } - String parts[] = entry.split(" ", 2); // Path may contain space - if (parts.length != 2 || parts[1].length() == 0) { - return null; // no space found or no file name - } - final String factList = parts[0]; - if (!factList.endsWith(";")) { - return null; - } - FTPFile file = new FTPFile(); - file.setRawListing(entry); - file.setName(parts[1]); - String[] facts = factList.split(";"); - boolean hasUnixMode = parts[0].toLowerCase(Locale.ENGLISH).contains("unix.mode="); - for (String fact : facts) { - String[] factparts = fact.split("=", -1); // Don't drop empty values - // Sample missing permission - // drwx------ 2 mirror mirror 4096 Mar 13 2010 subversion - // modify=20100313224553;perm=;type=dir;unique=811U282598;UNIX.group=500;UNIX.mode=0700;UNIX.owner=500; subversion - if (factparts.length != 2) { - return null; // invalid - there was no "=" sign - } - String factname = factparts[0].toLowerCase(Locale.ENGLISH); - String factvalue = factparts[1]; - if (factvalue.length() == 0) { - continue; // nothing to see here - } - String valueLowerCase = factvalue.toLowerCase(Locale.ENGLISH); - if ("size".equals(factname)) { - file.setSize(Long.parseLong(factvalue)); - } else if ("sizd".equals(factname)) { // Directory size - file.setSize(Long.parseLong(factvalue)); - } else if ("modify".equals(factname)) { - final Calendar parsed = parseGMTdateTime(factvalue); - if (parsed == null) { - return null; - } - file.setTimestamp(parsed); - } else if ("type".equals(factname)) { - Integer intType = TYPE_TO_INT.get(valueLowerCase); - if (intType == null) { - file.setType(FTPFile.UNKNOWN_TYPE); - } else { - file.setType(intType.intValue()); - } - } else if (factname.startsWith("unix.")) { - String unixfact = factname.substring("unix.".length()).toLowerCase(Locale.ENGLISH); - if ("group".equals(unixfact)) { - file.setGroup(factvalue); - } else if ("owner".equals(unixfact)) { - file.setUser(factvalue); - } else if ("mode".equals(unixfact)) { // e.g. 0[1]755 - int off = factvalue.length() - 3; // only parse last 3 digits - for (int i = 0; i < 3; i++) { - int ch = factvalue.charAt(off + i) - '0'; - if (ch >= 0 && ch <= 7) { // Check it's valid octal - for (int p : UNIX_PERMS[ch]) { - file.setPermission(UNIX_GROUPS[i], p, true); - } - } else { - // TODO should this cause failure, or can it be reported somehow? - } - } // digits - } // mode - } // unix. - else if (!hasUnixMode && "perm".equals(factname)) { // skip if we have the UNIX.mode - doUnixPerms(file, valueLowerCase); - } // process "perm" - } // each fact - return file; - } - - /** - * Parse a GMT time stamp of the form YYYYMMDDHHMMSS[.sss] - * - * @param timestamp the date-time to parse - * @return a Calendar entry, may be {@code null} - * @since 3.4 - */ - public static Calendar parseGMTdateTime(String timestamp) { - final SimpleDateFormat sdf; - final boolean hasMillis; - if (timestamp.contains(".")) { - sdf = new SimpleDateFormat("yyyyMMddHHmmss.SSS"); - hasMillis = true; - } else { - sdf = new SimpleDateFormat("yyyyMMddHHmmss"); - hasMillis = false; - } - TimeZone GMT = TimeZone.getTimeZone("GMT"); - // both timezones need to be set for the parse to work OK - sdf.setTimeZone(GMT); - GregorianCalendar gc = new GregorianCalendar(GMT); - ParsePosition pos = new ParsePosition(0); - sdf.setLenient(false); // We want to parse the whole string - final Date parsed = sdf.parse(timestamp, pos); - if (pos.getIndex() != timestamp.length()) { - return null; // did not fully parse the input - } - gc.setTime(parsed); - if (!hasMillis) { - gc.clear(Calendar.MILLISECOND); // flag up missing ms units - } - return gc; - } - - // perm-fact = "Perm" "=" *pvals - // pvals = "a" / "c" / "d" / "e" / "f" / - // "l" / "m" / "p" / "r" / "w" - private void doUnixPerms(FTPFile file, String valueLowerCase) { - for (char c : valueLowerCase.toCharArray()) { - // TODO these are mostly just guesses at present - switch (c) { - case 'a': // (file) may APPEnd - file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); - break; - case 'c': // (dir) files may be created in the dir - file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); - break; - case 'd': // deletable - file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); - break; - case 'e': // (dir) can change to this dir - file.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, true); - break; - case 'f': // (file) renamable - // ?? file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); - break; - case 'l': // (dir) can be listed - file.setPermission(FTPFile.USER_ACCESS, FTPFile.EXECUTE_PERMISSION, true); - break; - case 'm': // (dir) can create directory here - file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); - break; - case 'p': // (dir) entries may be deleted - file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); - break; - case 'r': // (files) file may be RETRieved - file.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, true); - break; - case 'w': // (files) file may be STORed - file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); - break; - default: - break; - // ignore unexpected flag for now. - } // switch - } // each char - } - - public static FTPFile parseEntry(String entry) { - return PARSER.parseFTPEntry(entry); - } - - public static MLSxEntryParser getInstance() { - return PARSER; - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/MVSFTPEntryParser.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/MVSFTPEntryParser.java deleted file mode 100644 index 85a01925..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/MVSFTPEntryParser.java +++ /dev/null @@ -1,537 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -import aria.apache.commons.net.ftp.FTPClientConfig; -import aria.apache.commons.net.ftp.FTPFile; -import aria.apache.commons.net.ftp.FTPFileEntryParser; -import java.text.ParseException; -import java.util.List; - -/** - * Implementation of FTPFileEntryParser and FTPFileListParser for IBM zOS/MVS - * Systems. - * - * @version $Id: MVSFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ - * @see FTPFileEntryParser FTPFileEntryParser (for - * usage instructions) - */ -public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { - - static final int UNKNOWN_LIST_TYPE = -1; - static final int FILE_LIST_TYPE = 0; - static final int MEMBER_LIST_TYPE = 1; - static final int UNIX_LIST_TYPE = 2; - static final int JES_LEVEL_1_LIST_TYPE = 3; - static final int JES_LEVEL_2_LIST_TYPE = 4; - - private int isType = UNKNOWN_LIST_TYPE; - - /** - * Fallback parser for Unix-style listings - */ - private UnixFTPEntryParser unixFTPEntryParser; - - /** - * Dates are ignored for file lists, but are used for member lists where - * possible - */ - static final String DEFAULT_DATE_FORMAT = "yyyy/MM/dd HH:mm"; // 2001/09/18 - // 13:52 - - /** - * Matches these entries: - *
-   *  Volume Unit    Referred Ext Used Recfm Lrecl BlkSz Dsorg Dsname
-   *  B10142 3390   2006/03/20  2   31  F       80    80  PS   MDI.OKL.WORK
-   * 
- */ - static final String FILE_LIST_REGEX = "\\S+\\s+" + // volume - // ignored - "\\S+\\s+" + // unit - ignored - "\\S+\\s+" + // access date - ignored - "\\S+\\s+" + // extents -ignored - "\\S+\\s+" + // used - ignored - "[FV]\\S*\\s+" + // recfm - must start with F or V - "\\S+\\s+" + // logical record length -ignored - "\\S+\\s+" + // block size - ignored - "(PS|PO|PO-E)\\s+" + // Dataset organisation. Many exist - // but only support: PS, PO, PO-E - "(\\S+)\\s*"; // Dataset Name (file name) - - /** - * Matches these entries: - *
-   *   Name      VV.MM   Created       Changed      Size  Init   Mod   Id
-   *   TBSHELF   01.03 2002/09/12 2002/10/11 09:37    11    11     0 KIL001
-   * 
- */ - static final String MEMBER_LIST_REGEX = "(\\S+)\\s+" + // name - "\\S+\\s+" + // version, modification (ignored) - "\\S+\\s+" + // create date (ignored) - "(\\S+)\\s+" + // modification date - "(\\S+)\\s+" + // modification time - "\\S+\\s+" + // size in lines (ignored) - "\\S+\\s+" + // size in lines at creation(ignored) - "\\S+\\s+" + // lines modified (ignored) - "\\S+\\s*"; // id of user who modified (ignored) - - /** - * Matches these entries, note: no header: - *
-   *   IBMUSER1  JOB01906  OUTPUT    3 Spool Files
-   *   012345678901234567890123456789012345678901234
-   *             1         2         3         4
-   * 
- */ - static final String JES_LEVEL_1_LIST_REGEX = "(\\S+)\\s+" + // job name ignored - "(\\S+)\\s+" + // job number - "(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE) - "(\\S+)\\s+" + // number of spool files - "(\\S+)\\s+" + // Text "Spool" ignored - "(\\S+)\\s*" // Text "Files" ignored - ; - - /** - * JES INTERFACE LEVEL 2 parser - * Matches these entries: - *
-   * JOBNAME  JOBID    OWNER    STATUS CLASS
-   * IBMUSER1 JOB01906 IBMUSER  OUTPUT A        RC=0000 3 spool files
-   * IBMUSER  TSU01830 IBMUSER  OUTPUT TSU      ABEND=522 3 spool files
-   * 
- * Sample output from FTP session: - *
-   * ftp> quote site filetype=jes
-   * 200 SITE command was accepted
-   * ftp> ls
-   * 200 Port request OK.
-   * 125 List started OK for JESJOBNAME=IBMUSER*, JESSTATUS=ALL and JESOWNER=IBMUSER
-   * JOBNAME  JOBID    OWNER    STATUS CLASS
-   * IBMUSER1 JOB01906 IBMUSER  OUTPUT A        RC=0000 3 spool files
-   * IBMUSER  TSU01830 IBMUSER  OUTPUT TSU      ABEND=522 3 spool files
-   * 250 List completed successfully.
-   * ftp> ls job01906
-   * 200 Port request OK.
-   * 125 List started OK for JESJOBNAME=IBMUSER*, JESSTATUS=ALL and JESOWNER=IBMUSER
-   * JOBNAME  JOBID    OWNER    STATUS CLASS
-   * IBMUSER1 JOB01906 IBMUSER  OUTPUT A        RC=0000
-   * --------
-   * ID  STEPNAME PROCSTEP C DDNAME   BYTE-COUNT
-   * 001 JES2              A JESMSGLG       858
-   * 002 JES2              A JESJCL         128
-   * 003 JES2              A JESYSMSG       443
-   * 3 spool files
-   * 250 List completed successfully.
-   * 
- */ - - static final String JES_LEVEL_2_LIST_REGEX = "(\\S+)\\s+" + // job name ignored - "(\\S+)\\s+" + // job number - "(\\S+)\\s+" + // owner ignored - "(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE) ignored - "(\\S+)\\s+" + // job class ignored - "(\\S+).*" // rest ignored - ; - - /* - * --------------------------------------------------------------------- - * Very brief and incomplete description of the zOS/MVS-filesystem. (Note: - * "zOS" is the operating system on the mainframe, and is the new name for - * MVS) - * - * The filesystem on the mainframe does not have hierarchal structure as for - * example the unix filesystem. For a more comprehensive description, please - * refer to the IBM manuals - * - * @LINK: - * http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/dgt2d440/CONTENTS - * - * - * Dataset names ============= - * - * A dataset name consist of a number of qualifiers separated by '.', each - * qualifier can be at most 8 characters, and the total length of a dataset - * can be max 44 characters including the dots. - * - * - * Dataset organisation ==================== - * - * A dataset represents a piece of storage allocated on one or more disks. - * The structure of the storage is described with the field dataset - * organinsation (DSORG). There are a number of dataset organisations, but - * only two are usable for FTP transfer. - * - * DSORG: PS: sequential, or flat file PO: partitioned dataset PO-E: - * extended partitioned dataset - * - * The PS file is just a flat file, as you would find it on the unix file - * system. - * - * The PO and PO-E files, can be compared to a single level directory - * structure. A PO file consist of a number of dataset members, or files if - * you will. It is possible to CD into the file, and to retrieve the - * individual members. - * - * - * Dataset record format ===================== - * - * The physical layout of the dataset is described on the dataset itself. - * There are a number of record formats (RECFM), but just a few is relavant - * for the FTP transfer. - * - * Any one beginning with either F or V can safely used by FTP transfer. All - * others should only be used with great care, so this version will just - * ignore the other record formats. F means a fixed number of records per - * allocated storage, and V means a variable number of records. - * - * - * Other notes =========== - * - * The file system supports automatically backup and retrieval of datasets. - * If a file is backed up, the ftp LIST command will return: ARCIVE Not - * Direct Access Device KJ.IOP998.ERROR.PL.UNITTEST - * - * - * Implementation notes ==================== - * - * Only datasets that have dsorg PS, PO or PO-E and have recfm beginning - * with F or V, is fully parsed. - * - * The following fields in FTPFile is used: FTPFile.Rawlisting: Always set. - * FTPFile.Type: DIRECTORY_TYPE or FILE_TYPE or UNKNOWN FTPFile.Name: name - * FTPFile.Timestamp: change time or null - * - * - * - * Additional information ====================== - * - * The MVS ftp server supports a number of features via the FTP interface. - * The features are controlled with the FTP command quote site filetype= - * SEQ is the default and used for normal file transfer JES is used to - * interact with the Job Entry Subsystem (JES) similar to a job scheduler - * DB2 is used to interact with a DB2 subsystem - * - * This parser supports SEQ and JES. - * - * - * - * - * - * - */ - - /** - * The sole constructor for a MVSFTPEntryParser object. - */ - public MVSFTPEntryParser() { - super(""); // note the regex is set in preParse. - super.configure(null); // configure parser with default configurations - } - - /** - * Parses a line of an z/OS - MVS FTP server file listing and converts it - * into a usable format in the form of an FTPFile instance. - * If the file listing line doesn't describe a file, then - * null is returned. Otherwise a FTPFile - * instance representing the file is returned. - * - * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - @Override public FTPFile parseFTPEntry(String entry) { - boolean isParsed = false; - FTPFile f = new FTPFile(); - - if (isType == FILE_LIST_TYPE) { - isParsed = parseFileList(f, entry); - } else if (isType == MEMBER_LIST_TYPE) { - isParsed = parseMemberList(f, entry); - if (!isParsed) { - isParsed = parseSimpleEntry(f, entry); - } - } else if (isType == UNIX_LIST_TYPE) { - isParsed = parseUnixList(f, entry); - } else if (isType == JES_LEVEL_1_LIST_TYPE) { - isParsed = parseJeslevel1List(f, entry); - } else if (isType == JES_LEVEL_2_LIST_TYPE) { - isParsed = parseJeslevel2List(f, entry); - } - - if (!isParsed) { - f = null; - } - - return f; - } - - /** - * Parse entries representing a dataset list. Only datasets with DSORG PS or - * PO or PO-E and with RECFM F* or V* will be parsed. - * - * Format of ZOS/MVS file list: 1 2 3 4 5 6 7 8 9 10 Volume Unit Referred - * Ext Used Recfm Lrecl BlkSz Dsorg Dsname B10142 3390 2006/03/20 2 31 F 80 - * 80 PS MDI.OKL.WORK ARCIVE Not Direct Access Device - * KJ.IOP998.ERROR.PL.UNITTEST B1N231 3390 2006/03/20 1 15 VB 256 27998 PO - * PLU B1N231 3390 2006/03/20 1 15 VB 256 27998 PO-E PLB - * - * ----------------------------------- Group within Regex [1] Volume [2] - * Unit [3] Referred [4] Ext: number of extents [5] Used [6] Recfm: Record - * format [7] Lrecl: Logical record length [8] BlkSz: Block size [9] Dsorg: - * Dataset organisation. Many exists but only support: PS, PO, PO-E [10] - * Dsname: Dataset name - * - * Note: When volume is ARCIVE, it means the dataset is stored somewhere in - * a tape archive. These entries is currently not supported by this parser. - * A null value is returned. - * - * @param file will be updated with Name, Type, Timestamp if parsed. - * @param entry zosDirectoryEntry - * @return true: entry was parsed, false: entry was not parsed. - */ - private boolean parseFileList(FTPFile file, String entry) { - if (matches(entry)) { - file.setRawListing(entry); - String name = group(2); - String dsorg = group(1); - file.setName(name); - - // DSORG - if ("PS".equals(dsorg)) { - file.setType(FTPFile.FILE_TYPE); - } else if ("PO".equals(dsorg) || "PO-E".equals(dsorg)) { - // regex already ruled out anything other than PO or PO-E - file.setType(FTPFile.DIRECTORY_TYPE); - } else { - return false; - } - - return true; - } - - return false; - } - - /** - * Parse entries within a partitioned dataset. - * - * Format of a memberlist within a PDS: - *
-   *    0         1        2          3        4     5     6      7    8
-   *   Name      VV.MM   Created       Changed      Size  Init   Mod   Id
-   *   TBSHELF   01.03 2002/09/12 2002/10/11 09:37    11    11     0 KIL001
-   *   TBTOOL    01.12 2002/09/12 2004/11/26 19:54    51    28     0 KIL001
-   *
-   * -------------------------------------------
-   * [1] Name
-   * [2] VV.MM: Version . modification
-   * [3] Created: yyyy / MM / dd
-   * [4,5] Changed: yyyy / MM / dd HH:mm
-   * [6] Size: number of lines
-   * [7] Init: number of lines when first created
-   * [8] Mod: number of modified lines a last save
-   * [9] Id: User id for last update
-   * 
- * - * @param file will be updated with Name, Type and Timestamp if parsed. - * @param entry zosDirectoryEntry - * @return true: entry was parsed, false: entry was not parsed. - */ - private boolean parseMemberList(FTPFile file, String entry) { - if (matches(entry)) { - file.setRawListing(entry); - String name = group(1); - String datestr = group(2) + " " + group(3); - file.setName(name); - file.setType(FTPFile.FILE_TYPE); - try { - file.setTimestamp(super.parseTimestamp(datestr)); - } catch (ParseException e) { - e.printStackTrace(); - // just ignore parsing errors. - // TODO check this is ok - return false; // this is a parsing failure too. - } - return true; - } - - return false; - } - - /** - * Assigns the name to the first word of the entry. Only to be used from a - * safe context, for example from a memberlist, where the regex for some - * reason fails. Then just assign the name field of FTPFile. - * - * @return true if the entry string is non-null and non-empty - */ - private boolean parseSimpleEntry(FTPFile file, String entry) { - if (entry != null && entry.trim().length() > 0) { - file.setRawListing(entry); - String name = entry.split(" ")[0]; - file.setName(name); - file.setType(FTPFile.FILE_TYPE); - return true; - } - return false; - } - - /** - * Parse the entry as a standard unix file. Using the UnixFTPEntryParser. - * - * @return true: entry is parsed, false: entry could not be parsed. - */ - private boolean parseUnixList(FTPFile file, String entry) { - file = unixFTPEntryParser.parseFTPEntry(entry); - if (file == null) { - return false; - } - return true; - } - - /** - * Matches these entries, note: no header: - *
-   * [1]      [2]      [3]   [4] [5]
-   * IBMUSER1 JOB01906 OUTPUT 3 Spool Files
-   * 012345678901234567890123456789012345678901234
-   *           1         2         3         4
-   * -------------------------------------------
-   * Group in regex
-   * [1] Job name
-   * [2] Job number
-   * [3] Job status (INPUT,ACTIVE,OUTPUT)
-   * [4] Number of sysout files
-   * [5] The string "Spool Files"
-   * 
- * - * @param file will be updated with Name, Type and Timestamp if parsed. - * @param entry zosDirectoryEntry - * @return true: entry was parsed, false: entry was not parsed. - */ - private boolean parseJeslevel1List(FTPFile file, String entry) { - if (matches(entry)) { - if (group(3).equalsIgnoreCase("OUTPUT")) { - file.setRawListing(entry); - String name = group(2); /* Job Number, used by GET */ - file.setName(name); - file.setType(FTPFile.FILE_TYPE); - return true; - } - } - - return false; - } - - /** - * Matches these entries: - *
-   * [1]      [2]      [3]     [4]    [5]
-   * JOBNAME  JOBID    OWNER   STATUS CLASS
-   * IBMUSER1 JOB01906 IBMUSER OUTPUT A       RC=0000 3 spool files
-   * IBMUSER  TSU01830 IBMUSER OUTPUT TSU     ABEND=522 3 spool files
-   * 012345678901234567890123456789012345678901234
-   *           1         2         3         4
-   * -------------------------------------------
-   * Group in regex
-   * [1] Job name
-   * [2] Job number
-   * [3] Owner
-   * [4] Job status (INPUT,ACTIVE,OUTPUT)
-   * [5] Job Class
-   * [6] The rest
-   * 
- * - * @param file will be updated with Name, Type and Timestamp if parsed. - * @param entry zosDirectoryEntry - * @return true: entry was parsed, false: entry was not parsed. - */ - private boolean parseJeslevel2List(FTPFile file, String entry) { - if (matches(entry)) { - if (group(4).equalsIgnoreCase("OUTPUT")) { - file.setRawListing(entry); - String name = group(2); /* Job Number, used by GET */ - file.setName(name); - file.setType(FTPFile.FILE_TYPE); - return true; - } - } - - return false; - } - - /** - * preParse is called as part of the interface. Per definition is is called - * before the parsing takes place. - * Three kind of lists is recognize: - * z/OS-MVS File lists - * z/OS-MVS Member lists - * unix file lists - * - * @since 2.0 - */ - @Override public List preParse(List orig) { - // simply remove the header line. Composite logic will take care of the - // two different types of - // list in short order. - if (orig != null && orig.size() > 0) { - String header = orig.get(0); - if (header.indexOf("Volume") >= 0 && header.indexOf("Dsname") >= 0) { - setType(FILE_LIST_TYPE); - super.setRegex(FILE_LIST_REGEX); - } else if (header.indexOf("Name") >= 0 && header.indexOf("Id") >= 0) { - setType(MEMBER_LIST_TYPE); - super.setRegex(MEMBER_LIST_REGEX); - } else if (header.indexOf("total") == 0) { - setType(UNIX_LIST_TYPE); - unixFTPEntryParser = new UnixFTPEntryParser(); - } else if (header.indexOf("Spool Files") >= 30) { - setType(JES_LEVEL_1_LIST_TYPE); - super.setRegex(JES_LEVEL_1_LIST_REGEX); - } else if (header.indexOf("JOBNAME") == 0 - && header.indexOf("JOBID") > 8) {// header contains JOBNAME JOBID OWNER // STATUS CLASS - setType(JES_LEVEL_2_LIST_TYPE); - super.setRegex(JES_LEVEL_2_LIST_REGEX); - } else { - setType(UNKNOWN_LIST_TYPE); - } - - if (isType != JES_LEVEL_1_LIST_TYPE) { // remove header is necessary - orig.remove(0); - } - } - - return orig; - } - - /** - * Explicitly set the type of listing being processed. - * - * @param type The listing type. - */ - void setType(int type) { - isType = type; - } - - /* - * @return - */ - @Override protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig(FTPClientConfig.SYST_MVS, DEFAULT_DATE_FORMAT, null); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/MacOsPeterFTPEntryParser.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/MacOsPeterFTPEntryParser.java deleted file mode 100644 index 2c8414d6..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/MacOsPeterFTPEntryParser.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -import aria.apache.commons.net.ftp.FTPClientConfig; -import aria.apache.commons.net.ftp.FTPFile; -import aria.apache.commons.net.ftp.FTPFileEntryParser; -import java.text.ParseException; - -/** - * Implementation FTPFileEntryParser and FTPFileListParser for pre MacOS-X Systems. - * - * @version $Id: MacOsPeterFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ - * @see FTPFileEntryParser FTPFileEntryParser (for usage instructions) - * @since 3.1 - */ -public class -MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { - - static final String DEFAULT_DATE_FORMAT = "MMM d yyyy"; //Nov 9 2001 - - static final String DEFAULT_RECENT_DATE_FORMAT = "MMM d HH:mm"; //Nov 9 20:06 - - /** - * this is the regular expression used by this parser. - * - * Permissions: - * r the file is readable - * w the file is writable - * x the file is executable - * - the indicated permission is not granted - * L mandatory locking occurs during access (the set-group-ID bit is - * on and the group execution bit is off) - * s the set-user-ID or set-group-ID bit is on, and the corresponding - * user or group execution bit is also on - * S undefined bit-state (the set-user-ID bit is on and the user - * execution bit is off) - * t the 1000 (octal) bit, or sticky bit, is on [see chmod(1)], and - * execution is on - * T the 1000 bit is turned on, and execution is off (undefined bit- - * state) - * e z/OS external link bit - */ - private static final String REGEX = "([bcdelfmpSs-])" - // type (1) - + "(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?\\s+" - // permission - + "(" - + "(folder\\s+)" - + "|" - + "((\\d+)\\s+(\\d+)\\s+)" - // resource size & data size - + ")" - + "(\\d+)\\s+" - // size - /* - * numeric or standard format date: - * yyyy-mm-dd (expecting hh:mm to follow) - * MMM [d]d - * [d]d MMM - * N.B. use non-space for MMM to allow for languages such as German which use - * diacritics (e.g. umlaut) in some abbreviations. - */ - + "((?:\\d+[-/]\\d+[-/]\\d+)|(?:\\S{3}\\s+\\d{1,2})|(?:\\d{1,2}\\s+\\S{3}))\\s+" - /* - year (for non-recent standard format) - yyyy - or time (for numeric or recent standard format) [h]h:mm - */ - + "(\\d+(?::\\d+)?)\\s+" - - + "(\\S*)(\\s*.*)"; // the rest - - /** - * The default constructor for a UnixFTPEntryParser object. - * - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public MacOsPeterFTPEntryParser() { - this(null); - } - - /** - * This constructor allows the creation of a UnixFTPEntryParser object with - * something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public MacOsPeterFTPEntryParser(FTPClientConfig config) { - super(REGEX); - configure(config); - } - - /** - * Parses a line of a unix (standard) FTP server file listing and converts - * it into a usable format in the form of an FTPFile - * instance. If the file listing line doesn't describe a file, - * null is returned, otherwise a FTPFile - * instance representing the files in the directory is returned. - * - * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - @Override public FTPFile parseFTPEntry(String entry) { - FTPFile file = new FTPFile(); - file.setRawListing(entry); - int type; - boolean isDevice = false; - - if (matches(entry)) { - String typeStr = group(1); - String hardLinkCount = "0"; - String usr = null; - String grp = null; - String filesize = group(20); - String datestr = group(21) + " " + group(22); - String name = group(23); - String endtoken = group(24); - - try { - file.setTimestamp(super.parseTimestamp(datestr)); - } catch (ParseException e) { - // intentionally do nothing - } - - // A 'whiteout' file is an ARTIFICIAL entry in any of several types of - // 'translucent' filesystems, of which a 'union' filesystem is one. - - // bcdelfmpSs- - switch (typeStr.charAt(0)) { - case 'd': - type = FTPFile.DIRECTORY_TYPE; - break; - case 'e': // NET-39 => z/OS external link - type = FTPFile.SYMBOLIC_LINK_TYPE; - break; - case 'l': - type = FTPFile.SYMBOLIC_LINK_TYPE; - break; - case 'b': - case 'c': - isDevice = true; - type = FTPFile.FILE_TYPE; // TODO change this if DEVICE_TYPE implemented - break; - case 'f': - case '-': - type = FTPFile.FILE_TYPE; - break; - default: // e.g. ? and w = whiteout - type = FTPFile.UNKNOWN_TYPE; - } - - file.setType(type); - - int g = 4; - for (int access = 0; access < 3; access++, g += 4) { - // Use != '-' to avoid having to check for suid and sticky bits - file.setPermission(access, FTPFile.READ_PERMISSION, (!group(g).equals("-"))); - file.setPermission(access, FTPFile.WRITE_PERMISSION, (!group(g + 1).equals("-"))); - - String execPerm = group(g + 2); - if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) { - file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true); - } else { - file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false); - } - } - - if (!isDevice) { - try { - file.setHardLinkCount(Integer.parseInt(hardLinkCount)); - } catch (NumberFormatException e) { - // intentionally do nothing - } - } - - file.setUser(usr); - file.setGroup(grp); - - try { - file.setSize(Long.parseLong(filesize)); - } catch (NumberFormatException e) { - // intentionally do nothing - } - - if (null == endtoken) { - file.setName(name); - } else { - // oddball cases like symbolic links, file names - // with spaces in them. - name += endtoken; - if (type == FTPFile.SYMBOLIC_LINK_TYPE) { - - int end = name.indexOf(" -> "); - // Give up if no link indicator is present - if (end == -1) { - file.setName(name); - } else { - file.setName(name.substring(0, end)); - file.setLink(name.substring(end + 4)); - } - } else { - file.setName(name); - } - } - return file; - } - return null; - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * - * @return the default configuration for this parser. - */ - @Override protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig(FTPClientConfig.SYST_UNIX, DEFAULT_DATE_FORMAT, - DEFAULT_RECENT_DATE_FORMAT); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/NTFTPEntryParser.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/NTFTPEntryParser.java deleted file mode 100644 index cee2811a..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/NTFTPEntryParser.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -import aria.apache.commons.net.ftp.Configurable; -import aria.apache.commons.net.ftp.FTPClientConfig; -import aria.apache.commons.net.ftp.FTPFile; -import aria.apache.commons.net.ftp.FTPFileEntryParser; -import java.text.ParseException; -import java.util.regex.Pattern; - -/** - * Implementation of FTPFileEntryParser and FTPFileListParser for NT Systems. - * - * @version $Id: NTFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ - * @see FTPFileEntryParser FTPFileEntryParser (for usage instructions) - */ -public class NTFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { - - private static final String DEFAULT_DATE_FORMAT = "MM-dd-yy hh:mma"; //11-09-01 12:30PM - - private static final String DEFAULT_DATE_FORMAT2 = "MM-dd-yy kk:mm"; //11-09-01 18:30 - - private final FTPTimestampParser timestampParser; - - /** - * this is the regular expression used by this parser. - */ - private static final String REGEX = - "(\\S+)\\s+(\\S+)\\s+" // MM-dd-yy whitespace hh:mma|kk:mm; swallow trailing spaces - + "(?:()|([0-9]+))\\s+" // or ddddd; swallow trailing spaces - + "(\\S.*)"; // First non-space followed by rest of line (name) - - /** - * The sole constructor for an NTFTPEntryParser object. - * - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public NTFTPEntryParser() { - this(null); - } - - /** - * This constructor allows the creation of an NTFTPEntryParser object - * with something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public NTFTPEntryParser(FTPClientConfig config) { - super(REGEX, Pattern.DOTALL); - configure(config); - FTPClientConfig config2 = - new FTPClientConfig(FTPClientConfig.SYST_NT, DEFAULT_DATE_FORMAT2, null); - config2.setDefaultDateFormatStr(DEFAULT_DATE_FORMAT2); - this.timestampParser = new FTPTimestampParserImpl(); - ((Configurable) this.timestampParser).configure(config2); - } - - /** - * Parses a line of an NT FTP server file listing and converts it into a - * usable format in the form of an FTPFile instance. If the - * file listing line doesn't describe a file, null is - * returned, otherwise a FTPFile instance representing the - * files in the directory is returned. - * - * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - @Override public FTPFile parseFTPEntry(String entry) { - FTPFile f = new FTPFile(); - f.setRawListing(entry); - - if (matches(entry)) { - String datestr = group(1) + " " + group(2); - String dirString = group(3); - String size = group(4); - String name = group(5); - try { - f.setTimestamp(super.parseTimestamp(datestr)); - } catch (ParseException e) { - // parsing fails, try the other date format - try { - f.setTimestamp(timestampParser.parseTimestamp(datestr)); - } catch (ParseException e2) { - // intentionally do nothing - } - } - - if (null == name || name.equals(".") || name.equals("..")) { - return (null); - } - f.setName(name); - - if ("".equals(dirString)) { - f.setType(FTPFile.DIRECTORY_TYPE); - f.setSize(0); - } else { - f.setType(FTPFile.FILE_TYPE); - if (null != size) { - f.setSize(Long.parseLong(size)); - } - } - return (f); - } - return null; - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * - * @return the default configuration for this parser. - */ - @Override public FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig(FTPClientConfig.SYST_NT, DEFAULT_DATE_FORMAT, null); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java deleted file mode 100644 index 7585ebbe..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -import aria.apache.commons.net.ftp.FTPClientConfig; -import aria.apache.commons.net.ftp.FTPFile; -import aria.apache.commons.net.ftp.FTPFileEntryParser; -import java.text.ParseException; - -/** - * Implementation of FTPFileEntryParser and FTPFileListParser for Netware Systems. Note that some of - * the proprietary - * extensions for Novell-specific operations are not supported. See - * - * http://www.novell.com/documentation/nw65/index.html?page=/documentation/nw65/ftp_enu/data/fbhbgcfa.html - * for more details. - * - * @version $Id: NetwareFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ - * @see FTPFileEntryParser FTPFileEntryParser (for usage instructions) - * @since 1.5 - */ -public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { - - /** - * Default date format is e.g. Feb 22 2006 - */ - private static final String DEFAULT_DATE_FORMAT = "MMM dd yyyy"; - - /** - * Default recent date format is e.g. Feb 22 17:32 - */ - private static final String DEFAULT_RECENT_DATE_FORMAT = "MMM dd HH:mm"; - - /** - * this is the regular expression used by this parser. - * Example: d [-W---F--] SCION_VOL2 512 Apr 13 23:12 VOL2 - */ - private static final String REGEX = "(d|-){1}\\s+" // Directory/file flag - + "\\[([-A-Z]+)\\]\\s+" // Attributes RWCEAFMS or - - + "(\\S+)\\s+" + "(\\d+)\\s+" // Owner and size - + "(\\S+\\s+\\S+\\s+((\\d+:\\d+)|(\\d{4})))" // Long/short date format - + "\\s+(.*)"; // Filename (incl. spaces) - - /** - * The default constructor for a NetwareFTPEntryParser object. - * - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public NetwareFTPEntryParser() { - this(null); - } - - /** - * This constructor allows the creation of an NetwareFTPEntryParser object - * with something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public NetwareFTPEntryParser(FTPClientConfig config) { - super(REGEX); - configure(config); - } - - /** - * Parses a line of an NetwareFTP server file listing and converts it into a - * usable format in the form of an FTPFile instance. If the - * file listing line doesn't describe a file, null is - * returned, otherwise a FTPFile instance representing the - * files in the directory is returned. - *

- * Netware file permissions are in the following format: RWCEAFMS, and are explained as follows: - *

    - *
  • S - Supervisor; All rights. - *
  • R - Read; Right to open and read or execute. - *
  • W - Write; Right to open and modify. - *
  • C - Create; Right to create; when assigned to a file, allows a deleted file to be - * recovered. - *
  • E - Erase; Right to delete. - *
  • M - Modify; Right to rename a file and to change attributes. - *
  • F - File Scan; Right to see directory or file listings. - *
  • A - Access Control; Right to modify trustee assignments and the Inherited Rights - * Mask. - *
- * - * See - * - * here - * for more details - * - * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - @Override public FTPFile parseFTPEntry(String entry) { - - FTPFile f = new FTPFile(); - if (matches(entry)) { - String dirString = group(1); - String attrib = group(2); - String user = group(3); - String size = group(4); - String datestr = group(5); - String name = group(9); - - try { - f.setTimestamp(super.parseTimestamp(datestr)); - } catch (ParseException e) { - // intentionally do nothing - } - - //is it a DIR or a file - if (dirString.trim().equals("d")) { - f.setType(FTPFile.DIRECTORY_TYPE); - } else // Should be "-" - { - f.setType(FTPFile.FILE_TYPE); - } - - f.setUser(user); - - //set the name - f.setName(name.trim()); - - //set the size - f.setSize(Long.parseLong(size.trim())); - - // Now set the permissions (or at least a subset thereof - full permissions would probably require - // subclassing FTPFile and adding extra metainformation there) - if (attrib.indexOf("R") != -1) { - f.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, true); - } - if (attrib.indexOf("W") != -1) { - f.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true); - } - - return (f); - } - return null; - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * - * @return the default configuration for this parser. - */ - @Override protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig(FTPClientConfig.SYST_NETWARE, DEFAULT_DATE_FORMAT, - DEFAULT_RECENT_DATE_FORMAT); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/OS2FTPEntryParser.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/OS2FTPEntryParser.java deleted file mode 100644 index fc2413e9..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/OS2FTPEntryParser.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -import aria.apache.commons.net.ftp.FTPClientConfig; -import aria.apache.commons.net.ftp.FTPFile; -import aria.apache.commons.net.ftp.FTPFileEntryParser; -import java.text.ParseException; - -/** - * Implementation of FTPFileEntryParser and FTPFileListParser for OS2 Systems. - * - * @version $Id: OS2FTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ - * @see FTPFileEntryParser FTPFileEntryParser (for usage instructions) - */ -public class OS2FTPEntryParser extends ConfigurableFTPFileEntryParserImpl - -{ - - private static final String DEFAULT_DATE_FORMAT = "MM-dd-yy HH:mm"; //11-09-01 12:30 - /** - * this is the regular expression used by this parser. - */ - private static final String REGEX = "\\s*([0-9]+)\\s*" - + "(\\s+|[A-Z]+)\\s*" - + "(DIR|\\s+)\\s*" - + "(\\S+)\\s+(\\S+)\\s+" /* date stuff */ - + "(\\S.*)"; - - /** - * The default constructor for a OS2FTPEntryParser object. - * - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public OS2FTPEntryParser() { - this(null); - } - - /** - * This constructor allows the creation of an OS2FTPEntryParser object - * with something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public OS2FTPEntryParser(FTPClientConfig config) { - super(REGEX); - configure(config); - } - - /** - * Parses a line of an OS2 FTP server file listing and converts it into a - * usable format in the form of an FTPFile instance. If the - * file listing line doesn't describe a file, null is - * returned, otherwise a FTPFile instance representing the - * files in the directory is returned. - * - * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - @Override public FTPFile parseFTPEntry(String entry) { - - FTPFile f = new FTPFile(); - if (matches(entry)) { - String size = group(1); - String attrib = group(2); - String dirString = group(3); - String datestr = group(4) + " " + group(5); - String name = group(6); - try { - f.setTimestamp(super.parseTimestamp(datestr)); - } catch (ParseException e) { - // intentionally do nothing - } - - //is it a DIR or a file - if (dirString.trim().equals("DIR") || attrib.trim().equals("DIR")) { - f.setType(FTPFile.DIRECTORY_TYPE); - } else { - f.setType(FTPFile.FILE_TYPE); - } - - //set the name - f.setName(name.trim()); - - //set the size - f.setSize(Long.parseLong(size.trim())); - - return (f); - } - return null; - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * - * @return the default configuration for this parser. - */ - @Override protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig(FTPClientConfig.SYST_OS2, DEFAULT_DATE_FORMAT, null); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/OS400FTPEntryParser.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/OS400FTPEntryParser.java deleted file mode 100644 index 43198267..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/OS400FTPEntryParser.java +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -import aria.apache.commons.net.ftp.FTPClientConfig; -import aria.apache.commons.net.ftp.FTPFile; -import java.io.File; -import java.text.ParseException; - -/** - * @version $Id: OS400FTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ - *
- *          Example *FILE/*MEM FTP entries, when the current
- *          working directory is a file of file system QSYS:
- *          ------------------------------------------------
- *
- *          $ cwd /qsys.lib/rpgunit.lib/rpgunitc1.file
- *            250-NAMEFMT set to 1.
- *            250 "/QSYS.LIB/RPGUNIT.LIB/RPGUNITC1.FILE" is current directory.
- *          $ dir
- *            227 Entering Passive Mode (10,200,36,33,40,249).
- *            125 List started.
- *            QPGMR          135168 22.06.13 13:18:19 *FILE
- *            QPGMR                                   *MEM       MKCMD.MBR
- *            QPGMR                                   *MEM       RUCALLTST.MBR
- *            QPGMR                                   *MEM       RUCMDHLP.MBR
- *            QPGMR                                   *MEM       RUCRTTST.MBR
- *            250 List completed.
- *
- *
- *          Example *FILE entry of an OS/400 save file:
- *          ---------------------------------------------------
- *
- *          $ cwd /qsys.lib/rpgunit.lib
- *            250 "/QSYS.LIB/RPGUNIT.LIB" is current library.
- *          $ dir rpgunit.file
- *            227 Entering Passive Mode (10,200,36,33,188,106).
- *            125 List started.
- *            QPGMR        16347136 29.06.13 15:45:09 *FILE      RPGUNIT.SAVF
- *            250 List completed.
- *
- *
- *          Example *STMF/*DIR FTP entries, when the
- *          current working directory is in file system "root":
- *          ---------------------------------------------------
- *
- *          $ cwd /home/raddatz
- *            250 "/home/raddatz" is current directory.
- *          $ dir test*
- *            227 Entering Passive Mode (10,200,36,33,200,189).
- *            125 List started.
- *            RADDATZ           200 21.05.11 12:31:18 *STMF      TEST_RG_02_CRLF.properties
- *            RADDATZ           187 08.05.11 12:31:40 *STMF      TEST_RG_02_LF.properties
- *            RADDATZ           187 08.05.11 12:31:52 *STMF      TEST_RG_02_CR.properties
- *            RADDATZ          8192 04.07.13 09:04:14 *DIR       testDir1/
- *            RADDATZ          8192 04.07.13 09:04:17 *DIR       testDir2/
- *            250 List completed.
- *
- *
- *          Example 1, using ANT to list specific members of a file:
- *          --------------------------------------------------------
- *
- *               <echo/>
- *               <echo>Listing members of a file:</echo>
- *
- *               <ftp action="list"
- *                    server="${ftp.server}"
- *                    userid="${ftp.user}"
- *                    password="${ftp.password}"
- *                    binary="false"
- *                    verbose="true"
- *                    remotedir="/QSYS.LIB/RPGUNIT.LIB/RPGUNITY1.FILE"
- *                    systemTypeKey="OS/400"
- *                    listing="ftp-listing.txt"
- *                    >
- *                   <fileset dir="./i5-downloads-file" casesensitive="false">
- *                       <include name="run*.mbr" />
- *                   </fileset>
- *               </ftp>
- *
- *          Output:
- *          -------
- *
- *            [echo] Listing members of a file:
- *             [ftp] listing files
- *             [ftp] listing RUN.MBR
- *             [ftp] listing RUNNER.MBR
- *             [ftp] listing RUNNERBND.MBR
- *             [ftp] 3 files listed
- *
- *
- *          Example 2, using ANT to list specific members of all files of a library:
- *          ------------------------------------------------------------------------
- *
- *               <echo/>
- *               <echo>Listing members of all files of a library:</echo>
- *
- *               <ftp action="list"
- *                    server="${ftp.server}"
- *                    userid="${ftp.user}"
- *                    password="${ftp.password}"
- *                    binary="false"
- *                    verbose="true"
- *                    remotedir="/QSYS.LIB/RPGUNIT.LIB"
- *                    systemTypeKey="OS/400"
- *                    listing="ftp-listing.txt"
- *                    >
- *                   <fileset dir="./i5-downloads-lib" casesensitive="false">
- *                       <include name="**\run*.mbr" />
- *                   </fileset>
- *               </ftp>
- *
- *          Output:
- *          -------
- *
- *            [echo] Listing members of all files of a library:
- *             [ftp] listing files
- *             [ftp] listing RPGUNIT1.FILE\RUN.MBR
- *             [ftp] listing RPGUNIT1.FILE\RUNRMT.MBR
- *             [ftp] listing RPGUNITT1.FILE\RUNT.MBR
- *             [ftp] listing RPGUNITY1.FILE\RUN.MBR
- *             [ftp] listing RPGUNITY1.FILE\RUNNER.MBR
- *             [ftp] listing RPGUNITY1.FILE\RUNNERBND.MBR
- *             [ftp] 6 files listed
- *
- *
- *          Example 3, using ANT to download specific members of a file:
- *          ------------------------------------------------------------
- *
- *               <echo/>
- *               <echo>Downloading members of a file:</echo>
- *
- *               <ftp action="get"
- *                    server="${ftp.server}"
- *                    userid="${ftp.user}"
- *                    password="${ftp.password}"
- *                    binary="false"
- *                    verbose="true"
- *                    remotedir="/QSYS.LIB/RPGUNIT.LIB/RPGUNITY1.FILE"
- *                    systemTypeKey="OS/400"
- *                    >
- *                   <fileset dir="./i5-downloads-file" casesensitive="false">
- *                       <include name="run*.mbr" />
- *                   </fileset>
- *               </ftp>
- *
- *          Output:
- *          -------
- *
- *            [echo] Downloading members of a file:
- *             [ftp] getting files
- *             [ftp] transferring RUN.MBR to C:\workspaces\rdp_080\workspace\ANT -
- *          FTP\i5-downloads-file\RUN.MBR
- *             [ftp] transferring RUNNER.MBR to C:\workspaces\rdp_080\workspace\ANT -
- *          FTP\i5-downloads-file\RUNNER.MBR
- *             [ftp] transferring RUNNERBND.MBR to C:\workspaces\rdp_080\workspace\ANT -
- *          FTP\i5-downloads-file\RUNNERBND.MBR
- *             [ftp] 3 files retrieved
- *
- *
- *          Example 4, using ANT to download specific members of all files of a library:
- *          ----------------------------------------------------------------------------
- *
- *               <echo/>
- *               <echo>Downloading members of all files of a library:</echo>
- *
- *               <ftp action="get"
- *                    server="${ftp.server}"
- *                    userid="${ftp.user}"
- *                    password="${ftp.password}"
- *                    binary="false"
- *                    verbose="true"
- *                    remotedir="/QSYS.LIB/RPGUNIT.LIB"
- *                    systemTypeKey="OS/400"
- *                    >
- *                   <fileset dir="./i5-downloads-lib" casesensitive="false">
- *                       <include name="**\run*.mbr" />
- *                   </fileset>
- *               </ftp>
- *
- *          Output:
- *          -------
- *
- *            [echo] Downloading members of all files of a library:
- *             [ftp] getting files
- *             [ftp] transferring RPGUNIT1.FILE\RUN.MBR to C:\work\rdp_080\space\ANT -
- *          FTP\i5-downloads\RPGUNIT1.FILE\RUN.MBR
- *             [ftp] transferring RPGUNIT1.FILE\RUNRMT.MBR to C:\work\rdp_080\space\ANT -
- *          FTP\i5-downloads\RPGUNIT1.FILE\RUNRMT.MBR
- *             [ftp] transferring RPGUNITT1.FILE\RUNT.MBR to C:\work\rdp_080\space\ANT -
- *          FTP\i5-downloads\RPGUNITT1.FILE\RUNT.MBR
- *             [ftp] transferring RPGUNITY1.FILE\RUN.MBR to C:\work\rdp_080\space\ANT -
- *          FTP\i5-downloads\RPGUNITY1.FILE\RUN.MBR
- *             [ftp] transferring RPGUNITY1.FILE\RUNNER.MBR to C:\work\rdp_080\space\ANT -
- *          FTP\i5-downloads\RPGUNITY1.FILE\RUNNER.MBR
- *             [ftp] transferring RPGUNITY1.FILE\RUNNERBND.MBR to C:\work\rdp_080\space\ANT -
- *          FTP\i5-downloads\RPGUNITY1.FILE\RUNNERBND.MBR
- *             [ftp] 6 files retrieved
- *
- *
- *          Example 5, using ANT to download a save file of a library:
- *          ----------------------------------------------------------
- *
- *               <ftp action="get"
- *                    server="${ftp.server}"
- *                    userid="${ftp.user}"
- *                    password="${ftp.password}"
- *                    binary="true"
- *                    verbose="true"
- *                    remotedir="/QSYS.LIB/RPGUNIT.LIB"
- *                    systemTypeKey="OS/400"
- *                    >
- *                 <fileset dir="./i5-downloads-savf" casesensitive="false">
- *                     <include name="RPGUNIT.SAVF" />
- *                 </fileset>
- *               </ftp>
- *
- *          Output:
- *          -------
- *            [echo] Downloading save file:
- *             [ftp] getting files
- *             [ftp] transferring RPGUNIT.SAVF to C:\workspaces\rdp_080\workspace\net-Test\i5-downloads-lib\RPGUNIT.SAVF
- *             [ftp] 1 files retrieved
- *
- *          
- */ -public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl { - private static final String DEFAULT_DATE_FORMAT = "yy/MM/dd HH:mm:ss"; //01/11/09 12:30:24 - - private static final String REGEX = "(\\S+)\\s+" // user - + "(?:(\\d+)\\s+)?" // size, empty for members - + "(?:(\\S+)\\s+(\\S+)\\s+)?" // date stuff, empty for members - + "(\\*STMF|\\*DIR|\\*FILE|\\*MEM)\\s+" // *STMF/*DIR/*FILE/*MEM - + "(?:(\\S+)\\s*)?"; // filename, missing, when CWD is a *FILE - - /** - * The default constructor for a OS400FTPEntryParser object. - * - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public OS400FTPEntryParser() { - this(null); - } - - /** - * This constructor allows the creation of an OS400FTPEntryParser object - * with something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public OS400FTPEntryParser(FTPClientConfig config) { - super(REGEX); - configure(config); - } - - @Override public FTPFile parseFTPEntry(String entry) { - - FTPFile file = new FTPFile(); - file.setRawListing(entry); - int type; - - if (matches(entry)) { - String usr = group(1); - String filesize = group(2); - String datestr = ""; - if (!isNullOrEmpty(group(3)) || !isNullOrEmpty(group(4))) { - datestr = group(3) + " " + group(4); - } - String typeStr = group(5); - String name = group(6); - - boolean mustScanForPathSeparator = true; - - try { - file.setTimestamp(super.parseTimestamp(datestr)); - } catch (ParseException e) { - // intentionally do nothing - } - - if (typeStr.equalsIgnoreCase("*STMF")) { - type = FTPFile.FILE_TYPE; - if (isNullOrEmpty(filesize) || isNullOrEmpty(name)) { - return null; - } - } else if (typeStr.equalsIgnoreCase("*DIR")) { - type = FTPFile.DIRECTORY_TYPE; - if (isNullOrEmpty(filesize) || isNullOrEmpty(name)) { - return null; - } - } else if (typeStr.equalsIgnoreCase("*FILE")) { - // File, defines the structure of the data (columns of a row) - // but the data is stored in one or more members. Typically a - // source file contains multiple members whereas it is - // recommended (but not enforced) to use one member per data - // file. - // Save files are a special type of files which are used - // to save objects, e.g. for backups. - if (name != null && name.toUpperCase().endsWith(".SAVF")) { - mustScanForPathSeparator = false; - type = FTPFile.FILE_TYPE; - } else { - return null; - } - } else if (typeStr.equalsIgnoreCase("*MEM")) { - mustScanForPathSeparator = false; - type = FTPFile.FILE_TYPE; - - if (isNullOrEmpty(name)) { - return null; - } - if (!(isNullOrEmpty(filesize) && isNullOrEmpty(datestr))) { - return null; - } - - // Quick and dirty bug fix to make SelectorUtils work. - // Class SelectorUtils uses 'File.separator' to splitt - // a given path into pieces. But actually it had to - // use the separator of the FTP server, which is a forward - // slash in case of an AS/400. - name = name.replace('/', File.separatorChar); - } else { - type = FTPFile.UNKNOWN_TYPE; - } - - file.setType(type); - - file.setUser(usr); - - try { - file.setSize(Long.parseLong(filesize)); - } catch (NumberFormatException e) { - // intentionally do nothing - } - - if (name.endsWith("/")) { - name = name.substring(0, name.length() - 1); - } - if (mustScanForPathSeparator) { - int pos = name.lastIndexOf('/'); - if (pos > -1) { - name = name.substring(pos + 1); - } - } - - file.setName(name); - - return file; - } - return null; - } - - /** - * @param string String value that is checked for null - * or empty. - * @return true for null or empty values, - * else false. - */ - private boolean isNullOrEmpty(String string) { - if (string == null || string.length() == 0) { - return true; - } - return false; - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * - * @return the default configuration for this parser. - */ - @Override protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig(FTPClientConfig.SYST_OS400, DEFAULT_DATE_FORMAT, null); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/ParserInitializationException.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/ParserInitializationException.java deleted file mode 100644 index 72576687..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/ParserInitializationException.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -/** - * This class encapsulates all errors that may be thrown by - * the process of an FTPFileEntryParserFactory creating and - * instantiating an FTPFileEntryParser. - */ -public class ParserInitializationException extends RuntimeException { - - private static final long serialVersionUID = 5563335279583210658L; - - /** - * Constucts a ParserInitializationException with just a message - * - * @param message Exception message - */ - public ParserInitializationException(String message) { - super(message); - } - - /** - * Constucts a ParserInitializationException with a message - * and a root cause. - * - * @param message Exception message - * @param rootCause root cause throwable that caused - * this to be thrown - */ - public ParserInitializationException(String message, Throwable rootCause) { - super(message, rootCause); - } - - /** - * returns the root cause of this exception or null - * if no root cause was specified. - * - * @return the root cause of this exception being thrown - * @deprecated use {@link #getCause()} instead - */ - @Deprecated public Throwable getRootCause() { - return super.getCause(); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java deleted file mode 100644 index 90100f89..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -import aria.apache.commons.net.ftp.FTPFileEntryParserImpl; -import java.util.regex.MatchResult; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -/** - * This abstract class implements both the older FTPFileListParser and - * newer FTPFileEntryParser interfaces with default functionality. - * All the classes in the parser subpackage inherit from this. - * - * This is the base class for all regular expression based FTPFileEntryParser classes - */ -public abstract class RegexFTPFileEntryParserImpl extends FTPFileEntryParserImpl { - /** - * internal pattern the matcher tries to match, representing a file - * entry - */ - private Pattern pattern = null; - - /** - * internal match result used by the parser - */ - private MatchResult result = null; - - /** - * Internal PatternMatcher object used by the parser. It has protected - * scope in case subclasses want to make use of it for their own purposes. - */ - protected Matcher _matcher_ = null; - - /** - * The constructor for a RegexFTPFileEntryParserImpl object. - * The expression is compiled with flags = 0. - * - * @param regex The regular expression with which this object is - * initialized. - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen in - * normal conditions. It it is seen, this is a sign that a subclass has - * been created with a bad regular expression. Since the parser must be - * created before use, this means that any bad parser subclasses created - * from this will bomb very quickly, leading to easy detection. - */ - - public RegexFTPFileEntryParserImpl(String regex) { - super(); - compileRegex(regex, 0); - } - - /** - * The constructor for a RegexFTPFileEntryParserImpl object. - * - * @param regex The regular expression with which this object is - * initialized. - * @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none. - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen in - * normal conditions. It it is seen, this is a sign that a subclass has - * been created with a bad regular expression. Since the parser must be - * created before use, this means that any bad parser subclasses created - * from this will bomb very quickly, leading to easy detection. - * @since 3.4 - */ - public RegexFTPFileEntryParserImpl(String regex, final int flags) { - super(); - compileRegex(regex, flags); - } - - /** - * Convenience method delegates to the internal MatchResult's matches() - * method. - * - * @param s the String to be matched - * @return true if s matches this object's regular expression. - */ - - public boolean matches(String s) { - this.result = null; - _matcher_ = pattern.matcher(s); - if (_matcher_.matches()) { - this.result = _matcher_.toMatchResult(); - } - return null != this.result; - } - - /** - * Convenience method - * - * @return the number of groups() in the internal MatchResult. - */ - - public int getGroupCnt() { - if (this.result == null) { - return 0; - } - return this.result.groupCount(); - } - - /** - * Convenience method delegates to the internal MatchResult's group() - * method. - * - * @param matchnum match group number to be retrieved - * @return the content of the matchnum'th group of the internal - * match or null if this method is called without a match having - * been made. - */ - public String group(int matchnum) { - if (this.result == null) { - return null; - } - return this.result.group(matchnum); - } - - /** - * For debugging purposes - returns a string shows each match group by - * number. - * - * @return a string shows each match group by number. - */ - - public String getGroupsAsString() { - StringBuilder b = new StringBuilder(); - for (int i = 1; i <= this.result.groupCount(); i++) { - b.append(i) - .append(") ") - .append(this.result.group(i)) - .append(System.getProperty("line.separator")); - } - return b.toString(); - } - - /** - * Alter the current regular expression being utilised for entry parsing - * and create a new {@link Pattern} instance. - * - * @param regex The new regular expression - * @return true - * @throws IllegalArgumentException if the regex cannot be compiled - * @since 2.0 - */ - public boolean setRegex(final String regex) { - compileRegex(regex, 0); - return true; - } - - /** - * Alter the current regular expression being utilised for entry parsing - * and create a new {@link Pattern} instance. - * - * @param regex The new regular expression - * @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none. - * @return true - * @throws IllegalArgumentException if the regex cannot be compiled - * @since 3.4 - */ - public boolean setRegex(final String regex, final int flags) { - compileRegex(regex, flags); - return true; - } - - /** - * Compile the regex and store the {@link Pattern}. - * - * This is an internal method to do the work so the constructor does not - * have to call an overrideable method. - * - * @param regex the expression to compile - * @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none. - * @throws IllegalArgumentException if the regex cannot be compiled - */ - private void compileRegex(final String regex, final int flags) { - try { - pattern = Pattern.compile(regex, flags); - } catch (PatternSyntaxException pse) { - throw new IllegalArgumentException("Unparseable regex supplied: " + regex); - } - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/UnixFTPEntryParser.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/UnixFTPEntryParser.java deleted file mode 100644 index 5e35f308..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/UnixFTPEntryParser.java +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -import aria.apache.commons.net.ftp.FTPClientConfig; -import aria.apache.commons.net.ftp.FTPFile; -import aria.apache.commons.net.ftp.FTPFileEntryParser; -import java.text.ParseException; -import java.util.List; -import java.util.ListIterator; - -/** - * Implementation FTPFileEntryParser and FTPFileListParser for standard - * Unix Systems. - * - * This class is based on the logic of Daniel Savarese's - * DefaultFTPListParser, but adapted to use regular expressions and to fit the - * new FTPFileEntryParser interface. - * - * @version $Id: UnixFTPEntryParser.java 1781925 2017-02-06 16:43:40Z sebb $ - * @see FTPFileEntryParser FTPFileEntryParser (for usage instructions) - */ -public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { - - static final String DEFAULT_DATE_FORMAT = "MMM d yyyy"; //Nov 9 2001 - - static final String DEFAULT_RECENT_DATE_FORMAT = "MMM d HH:mm"; //Nov 9 20:06 - - static final String NUMERIC_DATE_FORMAT = "yyyy-MM-dd HH:mm"; //2001-11-09 20:06 - - // Suffixes used in Japanese listings after the numeric values - private static final String JA_MONTH = "\u6708"; - private static final String JA_DAY = "\u65e5"; - private static final String JA_YEAR = "\u5e74"; - - private static final String DEFAULT_DATE_FORMAT_JA = - "M'" + JA_MONTH + "' d'" + JA_DAY + "' yyyy'" + JA_YEAR + "'"; //6月 3日 2003年 - - private static final String DEFAULT_RECENT_DATE_FORMAT_JA = - "M'" + JA_MONTH + "' d'" + JA_DAY + "' HH:mm"; //8月 17日 20:10 - - /** - * Some Linux distributions are now shipping an FTP server which formats - * file listing dates in an all-numeric format: - * "yyyy-MM-dd HH:mm. - * This is a very welcome development, and hopefully it will soon become - * the standard. However, since it is so new, for now, and possibly - * forever, we merely accomodate it, but do not make it the default. - *

- * For now end users may specify this format only via - * UnixFTPEntryParser(FTPClientConfig). - * Steve Cohen - 2005-04-17 - */ - public static final FTPClientConfig NUMERIC_DATE_CONFIG = - new FTPClientConfig(FTPClientConfig.SYST_UNIX, NUMERIC_DATE_FORMAT, null); - - /** - * this is the regular expression used by this parser. - * - * Permissions: - * r the file is readable - * w the file is writable - * x the file is executable - * - the indicated permission is not granted - * L mandatory locking occurs during access (the set-group-ID bit is - * on and the group execution bit is off) - * s the set-user-ID or set-group-ID bit is on, and the corresponding - * user or group execution bit is also on - * S undefined bit-state (the set-user-ID bit is on and the user - * execution bit is off) - * t the 1000 (octal) bit, or sticky bit, is on [see chmod(1)], and - * execution is on - * T the 1000 bit is turned on, and execution is off (undefined bit- - * state) - * e z/OS external link bit - * Final letter may be appended: - * + file has extended security attributes (e.g. ACL) - * Note: local listings on MacOSX also use '@'; - * this is not allowed for here as does not appear to be shown by FTP servers - * {@code @} file has extended attributes - */ - private static final String REGEX = "([bcdelfmpSs-])" // file type - + "(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?" // permissions - - + "\\s*" // separator TODO why allow it to be omitted?? - - + "(\\d+)" // link count - - + "\\s+" // separator - - + "(?:(\\S+(?:\\s\\S+)*?)\\s+)?" // owner name (optional spaces) - + "(?:(\\S+(?:\\s\\S+)*)\\s+)?" // group name (optional spaces) - + "(\\d+(?:,\\s*\\d+)?)" // size or n,m - - + "\\s+" // separator - - /* - * numeric or standard format date: - * yyyy-mm-dd (expecting hh:mm to follow) - * MMM [d]d - * [d]d MMM - * N.B. use non-space for MMM to allow for languages such as German which use - * diacritics (e.g. umlaut) in some abbreviations. - * Japanese uses numeric day and month with suffixes to distinguish them - * [d]dXX [d]dZZ - */ + "(" + "(?:\\d+[-/]\\d+[-/]\\d+)" + // yyyy-mm-dd - "|(?:\\S{3}\\s+\\d{1,2})" + // MMM [d]d - "|(?:\\d{1,2}\\s+\\S{3})" + // [d]d MMM - "|(?:\\d{1,2}" + JA_MONTH + "\\s+\\d{1,2}" + JA_DAY + ")" + ")" - - + "\\s+" // separator - - /* - year (for non-recent standard format) - yyyy - or time (for numeric or recent standard format) [h]h:mm - or Japanese year - yyyyXX - */ + "((?:\\d+(?::\\d+)?)|(?:\\d{4}" + JA_YEAR + "))" // (20) - - + "\\s" // separator - - + "(.*)"; // the rest (21) - - // if true, leading spaces are trimmed from file names - // this was the case for the original implementation - final boolean trimLeadingSpaces; // package protected for access from test code - - /** - * The default constructor for a UnixFTPEntryParser object. - * - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public UnixFTPEntryParser() { - this(null); - } - - /** - * This constructor allows the creation of a UnixFTPEntryParser object with - * something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public UnixFTPEntryParser(FTPClientConfig config) { - this(config, false); - } - - /** - * This constructor allows the creation of a UnixFTPEntryParser object with - * something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @param trimLeadingSpaces if {@code true}, trim leading spaces from file names - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 3.4 - */ - public UnixFTPEntryParser(FTPClientConfig config, boolean trimLeadingSpaces) { - super(REGEX); - configure(config); - this.trimLeadingSpaces = trimLeadingSpaces; - } - - /** - * Preparse the list to discard "total nnn" lines - */ - @Override public List preParse(List original) { - ListIterator iter = original.listIterator(); - while (iter.hasNext()) { - String entry = iter.next(); - if (entry.matches("^total \\d+$")) { // NET-389 - iter.remove(); - } - } - return original; - } - - /** - * Parses a line of a unix (standard) FTP server file listing and converts - * it into a usable format in the form of an FTPFile - * instance. If the file listing line doesn't describe a file, - * null is returned, otherwise a FTPFile - * instance representing the files in the directory is returned. - * - * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - @Override public FTPFile parseFTPEntry(String entry) { - FTPFile file = new FTPFile(); - file.setRawListing(entry); - int type; - boolean isDevice = false; - - if (matches(entry)) { - String typeStr = group(1); - String hardLinkCount = group(15); - String usr = group(16); - String grp = group(17); - String filesize = group(18); - String datestr = group(19) + " " + group(20); - String name = group(21); - if (trimLeadingSpaces) { - name = name.replaceFirst("^\\s+", ""); - } - - try { - if (group(19).contains(JA_MONTH)) { // special processing for Japanese format - FTPTimestampParserImpl jaParser = new FTPTimestampParserImpl(); - jaParser.configure(new FTPClientConfig(FTPClientConfig.SYST_UNIX, DEFAULT_DATE_FORMAT_JA, - DEFAULT_RECENT_DATE_FORMAT_JA)); - file.setTimestamp(jaParser.parseTimestamp(datestr)); - } else { - file.setTimestamp(super.parseTimestamp(datestr)); - } - } catch (ParseException e) { - // intentionally do nothing - } - - // A 'whiteout' file is an ARTIFICIAL entry in any of several types of - // 'translucent' filesystems, of which a 'union' filesystem is one. - - // bcdelfmpSs- - switch (typeStr.charAt(0)) { - case 'd': - type = FTPFile.DIRECTORY_TYPE; - break; - case 'e': // NET-39 => z/OS external link - type = FTPFile.SYMBOLIC_LINK_TYPE; - break; - case 'l': - type = FTPFile.SYMBOLIC_LINK_TYPE; - break; - case 'b': - case 'c': - isDevice = true; - type = FTPFile.FILE_TYPE; // TODO change this if DEVICE_TYPE implemented - break; - case 'f': - case '-': - type = FTPFile.FILE_TYPE; - break; - default: // e.g. ? and w = whiteout - type = FTPFile.UNKNOWN_TYPE; - } - - file.setType(type); - - int g = 4; - for (int access = 0; access < 3; access++, g += 4) { - // Use != '-' to avoid having to check for suid and sticky bits - file.setPermission(access, FTPFile.READ_PERMISSION, (!group(g).equals("-"))); - file.setPermission(access, FTPFile.WRITE_PERMISSION, (!group(g + 1).equals("-"))); - - String execPerm = group(g + 2); - if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) { - file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true); - } else { - file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false); - } - } - - if (!isDevice) { - try { - file.setHardLinkCount(Integer.parseInt(hardLinkCount)); - } catch (NumberFormatException e) { - // intentionally do nothing - } - } - - file.setUser(usr); - file.setGroup(grp); - - try { - file.setSize(Long.parseLong(filesize)); - } catch (NumberFormatException e) { - // intentionally do nothing - } - - // oddball cases like symbolic links, file names - // with spaces in them. - if (type == FTPFile.SYMBOLIC_LINK_TYPE) { - - int end = name.indexOf(" -> "); - // Give up if no link indicator is present - if (end == -1) { - file.setName(name); - } else { - file.setName(name.substring(0, end)); - file.setLink(name.substring(end + 4)); - } - } else { - file.setName(name); - } - return file; - } - return null; - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * - * @return the default configuration for this parser. - */ - @Override protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig(FTPClientConfig.SYST_UNIX, DEFAULT_DATE_FORMAT, - DEFAULT_RECENT_DATE_FORMAT); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/VMSFTPEntryParser.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/VMSFTPEntryParser.java deleted file mode 100644 index b2578cd0..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/VMSFTPEntryParser.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -import aria.apache.commons.net.ftp.FTPClientConfig; -import aria.apache.commons.net.ftp.FTPFile; -import aria.apache.commons.net.ftp.FTPFileEntryParser; -import aria.apache.commons.net.ftp.FTPListParseEngine; -import java.io.BufferedReader; -import java.io.IOException; -import java.text.ParseException; -import java.util.StringTokenizer; - -/** - * Implementation FTPFileEntryParser and FTPFileListParser for VMS Systems. - * This is a sample of VMS LIST output - * - * "1-JUN.LIS;1 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] - * (RWED,RWED,RWED,RE)", - * "1-JUN.LIS;2 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] - * (RWED,RWED,RWED,RE)", - * "DATA.DIR;1 1/9 2-JUN-1998 07:32:04 [GROUP,OWNER] - * (RWED,RWED,RWED,RE)", - *

- * Note: VMSFTPEntryParser can only be instantiated through the - * DefaultFTPParserFactory by classname. It will not be chosen - * by the autodetection scheme. - * - *

- * - * @version $Id: VMSFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ - * @see FTPFileEntryParser FTPFileEntryParser (for usage instructions) - * @see DefaultFTPFileEntryParserFactory - */ -public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { - - private static final String DEFAULT_DATE_FORMAT = "d-MMM-yyyy HH:mm:ss"; //9-NOV-2001 12:30:24 - - /** - * this is the regular expression used by this parser. - */ - private static final String REGEX = - "(.*?;[0-9]+)\\s*" //1 file and version - + "(\\d+)/\\d+\\s*" //2 size/allocated - + "(\\S+)\\s+(\\S+)\\s+" //3+4 date and time - + "\\[(([0-9$A-Za-z_]+)|([0-9$A-Za-z_]+),([0-9$a-zA-Z_]+))\\]?\\s*" //5(6,7,8) owner - + "\\([a-zA-Z]*,([a-zA-Z]*),([a-zA-Z]*),([a-zA-Z]*)\\)"; - //9,10,11 Permissions (O,G,W) - // TODO - perhaps restrict permissions to [RWED]* ? - - /** - * Constructor for a VMSFTPEntryParser object. - * - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public VMSFTPEntryParser() { - this(null); - } - - /** - * This constructor allows the creation of a VMSFTPEntryParser object with - * something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public VMSFTPEntryParser(FTPClientConfig config) { - super(REGEX); - configure(config); - } - - /** - * Parses a line of a VMS FTP server file listing and converts it into a - * usable format in the form of an FTPFile instance. If the - * file listing line doesn't describe a file, null is - * returned, otherwise a FTPFile instance representing the - * files in the directory is returned. - * - * @param entry A line of text from the file listing - * @return An FTPFile instance corresponding to the supplied entry - */ - @Override public FTPFile parseFTPEntry(String entry) { - //one block in VMS equals 512 bytes - long longBlock = 512; - - if (matches(entry)) { - FTPFile f = new FTPFile(); - f.setRawListing(entry); - String name = group(1); - String size = group(2); - String datestr = group(3) + " " + group(4); - String owner = group(5); - String permissions[] = new String[3]; - permissions[0] = group(9); - permissions[1] = group(10); - permissions[2] = group(11); - try { - f.setTimestamp(super.parseTimestamp(datestr)); - } catch (ParseException e) { - // intentionally do nothing - } - - String grp; - String user; - StringTokenizer t = new StringTokenizer(owner, ","); - switch (t.countTokens()) { - case 1: - grp = null; - user = t.nextToken(); - break; - case 2: - grp = t.nextToken(); - user = t.nextToken(); - break; - default: - grp = null; - user = null; - } - - if (name.lastIndexOf(".DIR") != -1) { - f.setType(FTPFile.DIRECTORY_TYPE); - } else { - f.setType(FTPFile.FILE_TYPE); - } - //set FTPFile name - //Check also for versions to be returned or not - if (isVersioning()) { - f.setName(name); - } else { - name = name.substring(0, name.lastIndexOf(";")); - f.setName(name); - } - //size is retreived in blocks and needs to be put in bytes - //for us humans and added to the FTPFile array - long sizeInBytes = Long.parseLong(size) * longBlock; - f.setSize(sizeInBytes); - - f.setGroup(grp); - f.setUser(user); - //set group and owner - - //Set file permission. - //VMS has (SYSTEM,OWNER,GROUP,WORLD) users that can contain - //R (read) W (write) E (execute) D (delete) - - //iterate for OWNER GROUP WORLD permissions - for (int access = 0; access < 3; access++) { - String permission = permissions[access]; - - f.setPermission(access, FTPFile.READ_PERMISSION, permission.indexOf('R') >= 0); - f.setPermission(access, FTPFile.WRITE_PERMISSION, permission.indexOf('W') >= 0); - f.setPermission(access, FTPFile.EXECUTE_PERMISSION, permission.indexOf('E') >= 0); - } - - return f; - } - return null; - } - - /** - * Reads the next entry using the supplied BufferedReader object up to - * whatever delemits one entry from the next. This parser cannot use - * the default implementation of simply calling BufferedReader.readLine(), - * because one entry may span multiple lines. - * - * @param reader The BufferedReader object from which entries are to be - * read. - * @return A string representing the next ftp entry or null if none found. - * @throws IOException thrown on any IO Error reading from the reader. - */ - @Override public String readNextEntry(BufferedReader reader) throws IOException { - String line = reader.readLine(); - StringBuilder entry = new StringBuilder(); - while (line != null) { - if (line.startsWith("Directory") || line.startsWith("Total")) { - line = reader.readLine(); - continue; - } - - entry.append(line); - if (line.trim().endsWith(")")) { - break; - } - line = reader.readLine(); - } - return (entry.length() == 0 ? null : entry.toString()); - } - - protected boolean isVersioning() { - return false; - } - - /** - * Defines a default configuration to be used when this class is - * instantiated without a {@link FTPClientConfig FTPClientConfig} - * parameter being specified. - * - * @return the default configuration for this parser. - */ - @Override protected FTPClientConfig getDefaultConfiguration() { - return new FTPClientConfig(FTPClientConfig.SYST_VMS, DEFAULT_DATE_FORMAT, null); - } - - // DEPRECATED METHODS - for API compatibility only - DO NOT USE - - /** - * DO NOT USE - * - * @param listStream the stream - * @return the array of files - * @throws IOException on error - * @deprecated (2.2) No other FTPFileEntryParser implementations have this method. - */ - @Deprecated public FTPFile[] parseFileList(java.io.InputStream listStream) throws IOException { - FTPListParseEngine engine = - new FTPListParseEngine(this); - engine.readServerList(listStream, null); - return engine.getFiles(); - } -} - -/* Emacs configuration - * Local variables: ** - * mode: java ** - * c-basic-offset: 4 ** - * indent-tabs-mode: nil ** - * End: ** - */ diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java deleted file mode 100644 index 948662a7..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.ftp.parser; - -import aria.apache.commons.net.ftp.FTPClientConfig; -import aria.apache.commons.net.ftp.FTPFileEntryParser; -import java.util.HashMap; -import java.util.List; -import java.util.ListIterator; -import java.util.regex.MatchResult; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -/** - * Special implementation VMSFTPEntryParser with versioning turned on. - * This parser removes all duplicates and only leaves the version with the highest - * version number for each filename. - * - * This is a sample of VMS LIST output - * - * "1-JUN.LIS;1 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] - * (RWED,RWED,RWED,RE)", - * "1-JUN.LIS;2 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] - * (RWED,RWED,RWED,RE)", - * "DATA.DIR;1 1/9 2-JUN-1998 07:32:04 [GROUP,OWNER] - * (RWED,RWED,RWED,RE)", - *

- * - * @version $Id: VMSVersioningFTPEntryParser.java 1747119 2016-06-07 02:22:24Z ggregory $ - * @see FTPFileEntryParser FTPFileEntryParser (for usage instructions) - */ -public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser { - - private final Pattern _preparse_pattern_; - private static final String PRE_PARSE_REGEX = "(.*?);([0-9]+)\\s*.*"; - - /** - * Constructor for a VMSFTPEntryParser object. - * - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - */ - public VMSVersioningFTPEntryParser() { - this(null); - } - - /** - * This constructor allows the creation of a VMSVersioningFTPEntryParser - * object with something other than the default configuration. - * - * @param config The {@link FTPClientConfig configuration} object used to - * configure this parser. - * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not - * be seen - * under normal conditions. It it is seen, this is a sign that - * REGEX is not a valid regular expression. - * @since 1.4 - */ - public VMSVersioningFTPEntryParser(FTPClientConfig config) { - super(); - configure(config); - try { - //_preparse_matcher_ = new Perl5Matcher(); - _preparse_pattern_ = Pattern.compile(PRE_PARSE_REGEX); - } catch (PatternSyntaxException pse) { - throw new IllegalArgumentException("Unparseable regex supplied: " + PRE_PARSE_REGEX); - } - } - - /** - * Implement hook provided for those implementers (such as - * VMSVersioningFTPEntryParser, and possibly others) which return - * multiple files with the same name to remove the duplicates .. - * - * @param original Original list - * @return Original list purged of duplicates - */ - @Override public List preParse(List original) { - HashMap existingEntries = new HashMap(); - ListIterator iter = original.listIterator(); - while (iter.hasNext()) { - String entry = iter.next().trim(); - MatchResult result = null; - Matcher _preparse_matcher_ = _preparse_pattern_.matcher(entry); - if (_preparse_matcher_.matches()) { - result = _preparse_matcher_.toMatchResult(); - String name = result.group(1); - String version = result.group(2); - Integer nv = Integer.valueOf(version); - Integer existing = existingEntries.get(name); - if (null != existing) { - if (nv.intValue() < existing.intValue()) { - iter.remove(); // removes older version from original list. - continue; - } - } - existingEntries.put(name, nv); - } - } - // we've now removed all entries less than with less than the largest - // version number for each name that were listed after the largest. - // we now must remove those with smaller than the largest version number - // for each name that were found before the largest - while (iter.hasPrevious()) { - String entry = iter.previous().trim(); - MatchResult result = null; - Matcher _preparse_matcher_ = _preparse_pattern_.matcher(entry); - if (_preparse_matcher_.matches()) { - result = _preparse_matcher_.toMatchResult(); - String name = result.group(1); - String version = result.group(2); - Integer nv = Integer.valueOf(version); - Integer existing = existingEntries.get(name); - if (null != existing) { - if (nv.intValue() < existing.intValue()) { - iter.remove(); // removes older version from original list. - } - } - } - } - return original; - } - - @Override protected boolean isVersioning() { - return true; - } -} - -/* Emacs configuration - * Local variables: ** - * mode: java ** - * c-basic-offset: 4 ** - * indent-tabs-mode: nil ** - * End: ** - */ diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/package-info.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/package-info.java deleted file mode 100644 index 147da7ad..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/ftp/parser/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -/** - * FTP file listing parser classes - */ -package aria.apache.commons.net.ftp.parser; \ No newline at end of file diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/CRLFLineReader.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/CRLFLineReader.java deleted file mode 100644 index 593214d7..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/CRLFLineReader.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.io; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; - -/** - * CRLFLineReader implements a readLine() method that requires - * exactly CRLF to terminate an input line. - * This is required for IMAP, which allows bare CR and LF. - * - * @since 3.0 - */ -public final class CRLFLineReader extends BufferedReader { - private static final char LF = '\n'; - private static final char CR = '\r'; - - /** - * Creates a CRLFLineReader that wraps an existing Reader - * input source. - * - * @param reader The Reader input source. - */ - public CRLFLineReader(Reader reader) { - super(reader); - } - - /** - * Read a line of text. - * A line is considered to be terminated by carriage return followed immediately by a linefeed. - * This contrasts with BufferedReader which also allows other combinations. - * - * @since 3.0 - */ - @Override public String readLine() throws IOException { - StringBuilder sb = new StringBuilder(); - int intch; - boolean prevWasCR = false; - synchronized (lock) { // make thread-safe (hopefully!) - while ((intch = read()) != -1) { - if (prevWasCR && intch == LF) { - return sb.substring(0, sb.length() - 1); - } - if (intch == CR) { - prevWasCR = true; - } else { - prevWasCR = false; - } - sb.append((char) intch); - } - } - String string = sb.toString(); - if (string.length() == 0) { // immediate EOF - return null; - } - return string; - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/CopyStreamAdapter.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/CopyStreamAdapter.java deleted file mode 100644 index 0f67dda9..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/CopyStreamAdapter.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.io; - -import java.util.EventListener; - -import aria.apache.commons.net.util.ListenerList; - -/** - * The CopyStreamAdapter will relay CopyStreamEvents to a list of listeners - * when either of its bytesTransferred() methods are called. Its purpose - * is to facilitate the notification of the progress of a copy operation - * performed by one of the static copyStream() methods in - * org.apache.commons.io.Util to multiple listeners. The static - * copyStream() methods invoke the - * bytesTransfered(long, int) of a CopyStreamListener for performance - * reasons and also because multiple listeners cannot be registered given - * that the methods are static. - * - * @version $Id: CopyStreamAdapter.java 1741829 2016-05-01 00:24:44Z sebb $ - * @see CopyStreamEvent - * @see CopyStreamListener - * @see Util - */ -public class CopyStreamAdapter implements CopyStreamListener { - private final ListenerList internalListeners; - - /** - * Creates a new copyStreamAdapter. - */ - public CopyStreamAdapter() { - internalListeners = new ListenerList(); - } - - /** - * This method is invoked by a CopyStreamEvent source after copying - * a block of bytes from a stream. The CopyStreamEvent will contain - * the total number of bytes transferred so far and the number of bytes - * transferred in the last write. The CopyStreamAdapater will relay - * the event to all of its registered listeners, listing itself as the - * source of the event. - * - * @param event The CopyStreamEvent fired by the copying of a block of - * bytes. - */ - @Override public void bytesTransferred(CopyStreamEvent event) { - for (EventListener listener : internalListeners) { - ((CopyStreamListener) (listener)).bytesTransferred(event); - } - } - - /** - * This method is not part of the JavaBeans model and is used by the - * static methods in the org.apache.commons.io.Util class for efficiency. - * It is invoked after a block of bytes to inform the listener of the - * transfer. The CopyStreamAdapater will create a CopyStreamEvent - * from the arguments and relay the event to all of its registered - * listeners, listing itself as the source of the event. - * - * @param totalBytesTransferred The total number of bytes transferred - * so far by the copy operation. - * @param bytesTransferred The number of bytes copied by the most recent - * write. - * @param streamSize The number of bytes in the stream being copied. - * This may be equal to CopyStreamEvent.UNKNOWN_STREAM_SIZE if - * the size is unknown. - */ - @Override public void bytesTransferred(long totalBytesTransferred, int bytesTransferred, - long streamSize) { - for (EventListener listener : internalListeners) { - ((CopyStreamListener) (listener)).bytesTransferred(totalBytesTransferred, bytesTransferred, - streamSize); - } - } - - /** - * Registers a CopyStreamListener to receive CopyStreamEvents. - * Although this method is not declared to be synchronized, it is - * implemented in a thread safe manner. - * - * @param listener The CopyStreamlistener to register. - */ - public void addCopyStreamListener(CopyStreamListener listener) { - internalListeners.addListener(listener); - } - - /** - * Unregisters a CopyStreamListener. Although this method is not - * synchronized, it is implemented in a thread safe manner. - * - * @param listener The CopyStreamlistener to unregister. - */ - public void removeCopyStreamListener(CopyStreamListener listener) { - internalListeners.removeListener(listener); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/CopyStreamEvent.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/CopyStreamEvent.java deleted file mode 100644 index f44d918e..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/CopyStreamEvent.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.io; - -import java.util.EventObject; - -/** - * A CopyStreamEvent is triggered after every write performed by a - * stream copying operation. The event stores the number of bytes - * transferred by the write triggering the event as well as the total - * number of bytes transferred so far by the copy operation. - * - * @version $Id: CopyStreamEvent.java 1652801 2015-01-18 17:10:05Z sebb $ - * @see CopyStreamListener - * @see CopyStreamAdapter - * @see Util - */ -public class CopyStreamEvent extends EventObject { - private static final long serialVersionUID = -964927635655051867L; - - /** - * Constant used to indicate the stream size is unknown. - */ - public static final long UNKNOWN_STREAM_SIZE = -1; - - private final int bytesTransferred; - private final long totalBytesTransferred; - private final long streamSize; - - /** - * Creates a new CopyStreamEvent instance. - * - * @param source The source of the event. - * @param totalBytesTransferred The total number of bytes transferred so - * far during a copy operation. - * @param bytesTransferred The number of bytes transferred during the - * write that triggered the CopyStreamEvent. - * @param streamSize The number of bytes in the stream being copied. - * This may be set to UNKNOWN_STREAM_SIZE if the - * size is unknown. - */ - public CopyStreamEvent(Object source, long totalBytesTransferred, int bytesTransferred, - long streamSize) { - super(source); - this.bytesTransferred = bytesTransferred; - this.totalBytesTransferred = totalBytesTransferred; - this.streamSize = streamSize; - } - - /** - * Returns the number of bytes transferred by the write that triggered - * the event. - * - * @return The number of bytes transferred by the write that triggered - * the vent. - */ - public int getBytesTransferred() { - return bytesTransferred; - } - - /** - * Returns the total number of bytes transferred so far by the copy - * operation. - * - * @return The total number of bytes transferred so far by the copy - * operation. - */ - public long getTotalBytesTransferred() { - return totalBytesTransferred; - } - - /** - * Returns the size of the stream being copied. - * This may be set to UNKNOWN_STREAM_SIZE if the - * size is unknown. - * - * @return The size of the stream being copied. - */ - public long getStreamSize() { - return streamSize; - } - - /** - * @since 3.0 - */ - @Override public String toString() { - return getClass().getName() - + "[source=" - + source - + ", total=" - + totalBytesTransferred - + ", bytes=" - + bytesTransferred - + ", size=" - + streamSize - + "]"; - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/CopyStreamException.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/CopyStreamException.java deleted file mode 100644 index 4314967c..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/CopyStreamException.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.io; - -import java.io.IOException; - -/** - * The CopyStreamException class is thrown by the org.apache.commons.io.Util - * copyStream() methods. It stores the number of bytes confirmed to - * have been transferred before an I/O error as well as the IOException - * responsible for the failure of a copy operation. - * - * @version $Id: CopyStreamException.java 1299238 2012-03-10 17:12:28Z sebb $ - * @see Util - */ -public class CopyStreamException extends IOException { - private static final long serialVersionUID = -2602899129433221532L; - - private final long totalBytesTransferred; - - /** - * Creates a new CopyStreamException instance. - * - * @param message A message describing the error. - * @param bytesTransferred The total number of bytes transferred before - * an exception was thrown in a copy operation. - * @param exception The IOException thrown during a copy operation. - */ - public CopyStreamException(String message, long bytesTransferred, IOException exception) { - super(message); - initCause(exception); // merge this into super() call once we need 1.6+ - totalBytesTransferred = bytesTransferred; - } - - /** - * Returns the total number of bytes confirmed to have - * been transferred by a failed copy operation. - * - * @return The total number of bytes confirmed to have - * been transferred by a failed copy operation. - */ - public long getTotalBytesTransferred() { - return totalBytesTransferred; - } - - /** - * Returns the IOException responsible for the failure of a copy operation. - * - * @return The IOException responsible for the failure of a copy operation. - */ - public IOException getIOException() { - return (IOException) getCause(); // cast is OK because it was initialised with an IOException - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/CopyStreamListener.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/CopyStreamListener.java deleted file mode 100644 index 14670feb..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/CopyStreamListener.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.io; - -import java.util.EventListener; - -/** - * The CopyStreamListener class can accept CopyStreamEvents to keep track - * of the progress of a stream copying operation. However, it is currently - * not used that way within NetComponents for performance reasons. Rather - * the bytesTransferred(long, int) method is called directly rather than - * passing an event to bytesTransferred(CopyStreamEvent), saving the creation - * of a CopyStreamEvent instance. Also, the only place where - * CopyStreamListener is currently used within NetComponents is in the - * static methods of the uninstantiable org.apache.commons.io.Util class, which - * would preclude the use of addCopyStreamListener and - * removeCopyStreamListener methods. However, future additions may use the - * JavaBean event model, which is why the hooks have been included from the - * beginning. - * - * @version $Id: CopyStreamListener.java 1652801 2015-01-18 17:10:05Z sebb $ - * @see CopyStreamEvent - * @see CopyStreamAdapter - * @see Util - */ -public interface CopyStreamListener extends EventListener { - /** - * This method is invoked by a CopyStreamEvent source after copying - * a block of bytes from a stream. The CopyStreamEvent will contain - * the total number of bytes transferred so far and the number of bytes - * transferred in the last write. - * - * @param event The CopyStreamEvent fired by the copying of a block of - * bytes. - */ - public void bytesTransferred(CopyStreamEvent event); - - /** - * This method is not part of the JavaBeans model and is used by the - * static methods in the org.apache.commons.io.Util class for efficiency. - * It is invoked after a block of bytes to inform the listener of the - * transfer. - * - * @param totalBytesTransferred The total number of bytes transferred - * so far by the copy operation. - * @param bytesTransferred The number of bytes copied by the most recent - * write. - * @param streamSize The number of bytes in the stream being copied. - * This may be equal to CopyStreamEvent.UNKNOWN_STREAM_SIZE if - * the size is unknown. - */ - public void bytesTransferred(long totalBytesTransferred, int bytesTransferred, long streamSize); -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/DotTerminatedMessageReader.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/DotTerminatedMessageReader.java deleted file mode 100644 index e554a359..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/DotTerminatedMessageReader.java +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.io; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; - -/** - * DotTerminatedMessageReader is a class used to read messages from a - * server that are terminated by a single dot followed by a - * <CR><LF> - * sequence and with double dots appearing at the begining of lines which - * do not signal end of message yet start with a dot. Various Internet - * protocols such as NNTP and POP3 produce messages of this type. - *

- * This class handles stripping of the duplicate period at the beginning - * of lines starting with a period, and ensures you cannot read past the end of the message. - *

- * Note: versions since 3.0 extend BufferedReader rather than Reader, - * and no longer change the CRLF into the local EOL. Also only DOT CR LF - * acts as EOF. - * - * @version $Id: DotTerminatedMessageReader.java 1747119 2016-06-07 02:22:24Z ggregory $ - */ -public final class DotTerminatedMessageReader extends BufferedReader { - private static final char LF = '\n'; - private static final char CR = '\r'; - private static final int DOT = '.'; - - private boolean atBeginning; - private boolean eof; - private boolean seenCR; // was last character CR? - - /** - * Creates a DotTerminatedMessageReader that wraps an existing Reader - * input source. - * - * @param reader The Reader input source containing the message. - */ - public DotTerminatedMessageReader(Reader reader) { - super(reader); - // Assumes input is at start of message - atBeginning = true; - eof = false; - } - - /** - * Reads and returns the next character in the message. If the end of the - * message has been reached, returns -1. Note that a call to this method - * may result in multiple reads from the underlying input stream to decode - * the message properly (removing doubled dots and so on). All of - * this is transparent to the programmer and is only mentioned for - * completeness. - * - * @return The next character in the message. Returns -1 if the end of the - * message has been reached. - * @throws IOException If an error occurs while reading the underlying - * stream. - */ - @Override public int read() throws IOException { - synchronized (lock) { - if (eof) { - return -1; // Don't allow read past EOF - } - int chint = super.read(); - if (chint == -1) { // True EOF - eof = true; - return -1; - } - if (atBeginning) { - atBeginning = false; - if (chint == DOT) { // Have DOT - mark(2); // need to check for CR LF or DOT - chint = super.read(); - if (chint == -1) { // Should not happen - // new Throwable("Trailing DOT").printStackTrace(); - eof = true; - return DOT; // return the trailing DOT - } - if (chint == DOT) { // Have DOT DOT - // no need to reset as we want to lose the first DOT - return chint; // i.e. DOT - } - if (chint == CR) { // Have DOT CR - chint = super.read(); - if (chint == -1) { // Still only DOT CR - should not happen - //new Throwable("Trailing DOT CR").printStackTrace(); - reset(); // So CR is picked up next time - return DOT; // return the trailing DOT - } - if (chint == LF) { // DOT CR LF - atBeginning = true; - eof = true; - // Do we need to clear the mark somehow? - return -1; - } - } - // Should not happen - lone DOT at beginning - //new Throwable("Lone DOT followed by "+(char)chint).printStackTrace(); - reset(); - return DOT; - } // have DOT - } // atBeginning - - // Handle CRLF in normal flow - if (seenCR) { - seenCR = false; - if (chint == LF) { - atBeginning = true; - } - } - if (chint == CR) { - seenCR = true; - } - return chint; - } - } - - /** - * Reads the next characters from the message into an array and - * returns the number of characters read. Returns -1 if the end of the - * message has been reached. - * - * @param buffer The character array in which to store the characters. - * @return The number of characters read. Returns -1 if the - * end of the message has been reached. - * @throws IOException If an error occurs in reading the underlying - * stream. - */ - @Override public int read(char[] buffer) throws IOException { - return read(buffer, 0, buffer.length); - } - - /** - * Reads the next characters from the message into an array and - * returns the number of characters read. Returns -1 if the end of the - * message has been reached. The characters are stored in the array - * starting from the given offset and up to the length specified. - * - * @param buffer The character array in which to store the characters. - * @param offset The offset into the array at which to start storing - * characters. - * @param length The number of characters to read. - * @return The number of characters read. Returns -1 if the - * end of the message has been reached. - * @throws IOException If an error occurs in reading the underlying - * stream. - */ - @Override public int read(char[] buffer, int offset, int length) throws IOException { - if (length < 1) { - return 0; - } - int ch; - synchronized (lock) { - if ((ch = read()) == -1) { - return -1; - } - - int off = offset; - - do { - buffer[offset++] = (char) ch; - } while (--length > 0 && (ch = read()) != -1); - - return (offset - off); - } - } - - /** - * Closes the message for reading. This doesn't actually close the - * underlying stream. The underlying stream may still be used for - * communicating with the server and therefore is not closed. - *

- * If the end of the message has not yet been reached, this method - * will read the remainder of the message until it reaches the end, - * so that the underlying stream may continue to be used properly - * for communicating with the server. If you do not fully read - * a message, you MUST close it, otherwise your program will likely - * hang or behave improperly. - * - * @throws IOException If an error occurs while reading the - * underlying stream. - */ - @Override public void close() throws IOException { - synchronized (lock) { - if (!eof) { - while (read() != -1) { - // read to EOF - } - } - eof = true; - atBeginning = false; - } - } - - /** - * Read a line of text. - * A line is considered to be terminated by carriage return followed immediately by a linefeed. - * This contrasts with BufferedReader which also allows other combinations. - * - * @since 3.0 - */ - @Override public String readLine() throws IOException { - StringBuilder sb = new StringBuilder(); - int intch; - synchronized (lock) { // make thread-safe (hopefully!) - while ((intch = read()) != -1) { - if (intch == LF && atBeginning) { - return sb.substring(0, sb.length() - 1); - } - sb.append((char) intch); - } - } - String string = sb.toString(); - if (string.length() == 0) { // immediate EOF - return null; - } - // Should not happen - EOF without CRLF - //new Throwable(string).printStackTrace(); - return string; - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/DotTerminatedMessageWriter.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/DotTerminatedMessageWriter.java deleted file mode 100644 index 637399bd..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/DotTerminatedMessageWriter.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.io; - -import java.io.IOException; -import java.io.Writer; - -/*** - * DotTerminatedMessageWriter is a class used to write messages to a - * server that are terminated by a single dot followed by a - * <CR><LF> - * sequence and with double dots appearing at the begining of lines which - * do not signal end of message yet start with a dot. Various Internet - * protocols such as NNTP and POP3 produce messages of this type. - *

- * This class handles the doubling of line-starting periods, - * converts single linefeeds to NETASCII newlines, and on closing - * will send the final message terminator dot and NETASCII newline - * sequence. - * - * - ***/ - -public final class DotTerminatedMessageWriter extends Writer { - private static final int __NOTHING_SPECIAL_STATE = 0; - private static final int __LAST_WAS_CR_STATE = 1; - private static final int __LAST_WAS_NL_STATE = 2; - - private int __state; - private Writer __output; - - /*** - * Creates a DotTerminatedMessageWriter that wraps an existing Writer - * output destination. - * - * @param output The Writer output destination to write the message. - ***/ - public DotTerminatedMessageWriter(Writer output) { - super(output); - __output = output; - __state = __NOTHING_SPECIAL_STATE; - } - - /*** - * Writes a character to the output. Note that a call to this method - * may result in multiple writes to the underling Writer in order to - * convert naked linefeeds to NETASCII line separators and to double - * line-leading periods. This is transparent to the programmer and - * is only mentioned for completeness. - * - * @param ch The character to write. - * @throws IOException If an error occurs while writing to the - * underlying output. - ***/ - @Override public void write(int ch) throws IOException { - synchronized (lock) { - switch (ch) { - case '\r': - __state = __LAST_WAS_CR_STATE; - __output.write('\r'); - return; - case '\n': - if (__state != __LAST_WAS_CR_STATE) { - __output.write('\r'); - } - __output.write('\n'); - __state = __LAST_WAS_NL_STATE; - return; - case '.': - // Double the dot at the beginning of a line - if (__state == __LAST_WAS_NL_STATE) { - __output.write('.'); - } - //$FALL-THROUGH$ - default: - __state = __NOTHING_SPECIAL_STATE; - __output.write(ch); - return; - } - } - } - - /*** - * Writes a number of characters from a character array to the output - * starting from a given offset. - * - * @param buffer The character array to write. - * @param offset The offset into the array at which to start copying data. - * @param length The number of characters to write. - * @throws IOException If an error occurs while writing to the underlying - * output. - ***/ - @Override public void write(char[] buffer, int offset, int length) throws IOException { - synchronized (lock) { - while (length-- > 0) { - write(buffer[offset++]); - } - } - } - - /*** - * Writes a character array to the output. - * - * @param buffer The character array to write. - * @throws IOException If an error occurs while writing to the underlying - * output. - ***/ - @Override public void write(char[] buffer) throws IOException { - write(buffer, 0, buffer.length); - } - - /*** - * Writes a String to the output. - * - * @param string The String to write. - * @throws IOException If an error occurs while writing to the underlying - * output. - ***/ - @Override public void write(String string) throws IOException { - write(string.toCharArray()); - } - - /*** - * Writes part of a String to the output starting from a given offset. - * - * @param string The String to write. - * @param offset The offset into the String at which to start copying data. - * @param length The number of characters to write. - * @throws IOException If an error occurs while writing to the underlying - * output. - ***/ - @Override public void write(String string, int offset, int length) throws IOException { - write(string.toCharArray(), offset, length); - } - - /*** - * Flushes the underlying output, writing all buffered output. - * - * @throws IOException If an error occurs while writing to the underlying - * output. - ***/ - @Override public void flush() throws IOException { - synchronized (lock) { - __output.flush(); - } - } - - /*** - * Flushes the underlying output, writing all buffered output, but doesn't - * actually close the underlying stream. The underlying stream may still - * be used for communicating with the server and therefore is not closed. - * - * @throws IOException If an error occurs while writing to the underlying - * output or closing the Writer. - ***/ - @Override public void close() throws IOException { - synchronized (lock) { - if (__output == null) { - return; - } - - if (__state == __LAST_WAS_CR_STATE) { - __output.write('\n'); - } else if (__state != __LAST_WAS_NL_STATE) { - __output.write("\r\n"); - } - - __output.write(".\r\n"); - - __output.flush(); - __output = null; - } - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/FromNetASCIIInputStream.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/FromNetASCIIInputStream.java deleted file mode 100644 index f8aeeded..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/FromNetASCIIInputStream.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.io; - -import java.io.IOException; -import java.io.InputStream; -import java.io.PushbackInputStream; -import java.io.UnsupportedEncodingException; - -/*** - * This class wraps an input stream, replacing all occurrences - * of <CR><LF> (carriage return followed by a linefeed), - * which is the NETASCII standard for representing a newline, with the - * local line separator representation. You would use this class to - * implement ASCII file transfers requiring conversion from NETASCII. - * - * - ***/ - -public final class FromNetASCIIInputStream extends PushbackInputStream { - static final boolean _noConversionRequired; - static final String _lineSeparator; - static final byte[] _lineSeparatorBytes; - - static { - _lineSeparator = System.getProperty("line.separator"); - _noConversionRequired = _lineSeparator.equals("\r\n"); - try { - _lineSeparatorBytes = _lineSeparator.getBytes("US-ASCII"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("Broken JVM - cannot find US-ASCII charset!", e); - } - } - - private int __length = 0; - - /*** - * Returns true if the NetASCII line separator differs from the system - * line separator, false if they are the same. This method is useful - * to determine whether or not you need to instantiate a - * FromNetASCIIInputStream object. - * - * @return True if the NETASCII line separator differs from the local - * system line separator, false if they are the same. - ***/ - public static final boolean isConversionRequired() { - return !_noConversionRequired; - } - - /*** - * Creates a FromNetASCIIInputStream instance that wraps an existing - * InputStream. - * @param input the stream to wrap - ***/ - public FromNetASCIIInputStream(InputStream input) { - super(input, _lineSeparatorBytes.length + 1); - } - - private int __read() throws IOException { - int ch; - - ch = super.read(); - - if (ch == '\r') { - ch = super.read(); - if (ch == '\n') { - unread(_lineSeparatorBytes); - ch = super.read(); - // This is a kluge for read(byte[], ...) to read the right amount - --__length; - } else { - if (ch != -1) { - unread(ch); - } - return '\r'; - } - } - - return ch; - } - - /*** - * Reads and returns the next byte in the stream. If the end of the - * message has been reached, returns -1. Note that a call to this method - * may result in multiple reads from the underlying input stream in order - * to convert NETASCII line separators to the local line separator format. - * This is transparent to the programmer and is only mentioned for - * completeness. - * - * @return The next character in the stream. Returns -1 if the end of the - * stream has been reached. - * @throws IOException If an error occurs while reading the underlying - * stream. - ***/ - @Override public int read() throws IOException { - if (_noConversionRequired) { - return super.read(); - } - - return __read(); - } - - /*** - * Reads the next number of bytes from the stream into an array and - * returns the number of bytes read. Returns -1 if the end of the - * stream has been reached. - * - * @param buffer The byte array in which to store the data. - * @return The number of bytes read. Returns -1 if the - * end of the message has been reached. - * @throws IOException If an error occurs in reading the underlying - * stream. - ***/ - @Override public int read(byte buffer[]) throws IOException { - return read(buffer, 0, buffer.length); - } - - /*** - * Reads the next number of bytes from the stream into an array and returns - * the number of bytes read. Returns -1 if the end of the - * message has been reached. The characters are stored in the array - * starting from the given offset and up to the length specified. - * - * @param buffer The byte array in which to store the data. - * @param offset The offset into the array at which to start storing data. - * @param length The number of bytes to read. - * @return The number of bytes read. Returns -1 if the - * end of the stream has been reached. - * @throws IOException If an error occurs while reading the underlying - * stream. - ***/ - @Override public int read(byte buffer[], int offset, int length) throws IOException { - if (_noConversionRequired) { - return super.read(buffer, offset, length); - } - - if (length < 1) { - return 0; - } - - int ch, off; - - ch = available(); - - __length = (length > ch ? ch : length); - - // If nothing is available, block to read only one character - if (__length < 1) { - __length = 1; - } - - if ((ch = __read()) == -1) { - return -1; - } - - off = offset; - - do { - buffer[offset++] = (byte) ch; - } while (--__length > 0 && (ch = __read()) != -1); - - return (offset - off); - } - - // PushbackInputStream in JDK 1.1.3 returns the wrong thing - // TODO - can we delete this override now? - - /*** - * Returns the number of bytes that can be read without blocking EXCEPT - * when newline conversions have to be made somewhere within the - * available block of bytes. In other words, you really should not - * rely on the value returned by this method if you are trying to avoid - * blocking. - ***/ - @Override public int available() throws IOException { - if (in == null) { - throw new IOException("Stream closed"); - } - return (buf.length - pos) + in.available(); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/FromNetASCIIOutputStream.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/FromNetASCIIOutputStream.java deleted file mode 100644 index 85e6112d..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/FromNetASCIIOutputStream.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.io; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/*** - * This class wraps an output stream, replacing all occurrences - * of <CR><LF> (carriage return followed by a linefeed), - * which is the NETASCII standard for representing a newline, with the - * local line separator representation. You would use this class to - * implement ASCII file transfers requiring conversion from NETASCII. - *

- * Because of the translation process, a call to flush() will - * not flush the last byte written if that byte was a carriage - * return. A call to {@link #close close() }, however, will - * flush the carriage return. - * - * - ***/ - -public final class FromNetASCIIOutputStream extends FilterOutputStream { - private boolean __lastWasCR; - - /*** - * Creates a FromNetASCIIOutputStream instance that wraps an existing - * OutputStream. - * - * @param output The OutputStream to wrap. - ***/ - public FromNetASCIIOutputStream(OutputStream output) { - super(output); - __lastWasCR = false; - } - - private void __write(int ch) throws IOException { - switch (ch) { - case '\r': - __lastWasCR = true; - // Don't write anything. We need to see if next one is linefeed - break; - case '\n': - if (__lastWasCR) { - out.write(FromNetASCIIInputStream._lineSeparatorBytes); - __lastWasCR = false; - break; - } - __lastWasCR = false; - out.write('\n'); - break; - default: - if (__lastWasCR) { - out.write('\r'); - __lastWasCR = false; - } - out.write(ch); - break; - } - } - - /*** - * Writes a byte to the stream. Note that a call to this method - * might not actually write a byte to the underlying stream until a - * subsequent character is written, from which it can be determined if - * a NETASCII line separator was encountered. - * This is transparent to the programmer and is only mentioned for - * completeness. - * - * @param ch The byte to write. - * @throws IOException If an error occurs while writing to the underlying - * stream. - ***/ - @Override public synchronized void write(int ch) throws IOException { - if (FromNetASCIIInputStream._noConversionRequired) { - out.write(ch); - return; - } - - __write(ch); - } - - /*** - * Writes a byte array to the stream. - * - * @param buffer The byte array to write. - * @throws IOException If an error occurs while writing to the underlying - * stream. - ***/ - @Override public synchronized void write(byte buffer[]) throws IOException { - write(buffer, 0, buffer.length); - } - - /*** - * Writes a number of bytes from a byte array to the stream starting from - * a given offset. - * - * @param buffer The byte array to write. - * @param offset The offset into the array at which to start copying data. - * @param length The number of bytes to write. - * @throws IOException If an error occurs while writing to the underlying - * stream. - ***/ - @Override public synchronized void write(byte buffer[], int offset, int length) - throws IOException { - if (FromNetASCIIInputStream._noConversionRequired) { - // FilterOutputStream method is very slow. - //super.write(buffer, offset, length); - out.write(buffer, offset, length); - return; - } - - while (length-- > 0) { - __write(buffer[offset++]); - } - } - - /*** - * Closes the stream, writing all pending data. - * - * @throws IOException If an error occurs while closing the stream. - ***/ - @Override public synchronized void close() throws IOException { - if (FromNetASCIIInputStream._noConversionRequired) { - super.close(); - return; - } - - if (__lastWasCR) { - out.write('\r'); - } - super.close(); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/SocketInputStream.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/SocketInputStream.java deleted file mode 100644 index 531e4029..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/SocketInputStream.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.io; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.Socket; - -/*** - * This class wraps an input stream, storing a reference to its originating - * socket. When the stream is closed, it will also close the socket - * immediately afterward. This class is useful for situations where you - * are dealing with a stream originating from a socket, but do not have - * a reference to the socket, and want to make sure it closes when the - * stream closes. - * - * - * @see SocketOutputStream - ***/ - -public class SocketInputStream extends FilterInputStream { - private final Socket __socket; - - /*** - * Creates a SocketInputStream instance wrapping an input stream and - * storing a reference to a socket that should be closed on closing - * the stream. - * - * @param socket The socket to close on closing the stream. - * @param stream The input stream to wrap. - ***/ - public SocketInputStream(Socket socket, InputStream stream) { - super(stream); - __socket = socket; - } - - /*** - * Closes the stream and immediately afterward closes the referenced - * socket. - * - * @throws IOException If there is an error in closing the stream - * or socket. - ***/ - @Override public void close() throws IOException { - super.close(); - __socket.close(); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/SocketOutputStream.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/SocketOutputStream.java deleted file mode 100644 index 3393ded7..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/SocketOutputStream.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.io; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.net.Socket; - -/*** - * This class wraps an output stream, storing a reference to its originating - * socket. When the stream is closed, it will also close the socket - * immediately afterward. This class is useful for situations where you - * are dealing with a stream originating from a socket, but do not have - * a reference to the socket, and want to make sure it closes when the - * stream closes. - * - * - * @see SocketInputStream - ***/ - -public class SocketOutputStream extends FilterOutputStream { - private final Socket __socket; - - /*** - * Creates a SocketOutputStream instance wrapping an output stream and - * storing a reference to a socket that should be closed on closing - * the stream. - * - * @param socket The socket to close on closing the stream. - * @param stream The input stream to wrap. - ***/ - public SocketOutputStream(Socket socket, OutputStream stream) { - super(stream); - __socket = socket; - } - - /*** - * Writes a number of bytes from a byte array to the stream starting from - * a given offset. This method bypasses the equivalent method in - * FilterOutputStream because the FilterOutputStream implementation is - * very inefficient. - * - * @param buffer The byte array to write. - * @param offset The offset into the array at which to start copying data. - * @param length The number of bytes to write. - * @throws IOException If an error occurs while writing to the underlying - * stream. - ***/ - @Override public void write(byte buffer[], int offset, int length) throws IOException { - out.write(buffer, offset, length); - } - - /*** - * Closes the stream and immediately afterward closes the referenced - * socket. - * - * @throws IOException If there is an error in closing the stream - * or socket. - ***/ - @Override public void close() throws IOException { - super.close(); - __socket.close(); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/ToNetASCIIInputStream.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/ToNetASCIIInputStream.java deleted file mode 100644 index e7ee8bc5..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/ToNetASCIIInputStream.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.io; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - -/*** - * This class wraps an input stream, replacing all singly occurring - * <LF> (linefeed) characters with <CR><LF> (carriage return - * followed by linefeed), which is the NETASCII standard for representing - * a newline. - * You would use this class to implement ASCII file transfers requiring - * conversion to NETASCII. - * - * - ***/ - -public final class ToNetASCIIInputStream extends FilterInputStream { - private static final int __NOTHING_SPECIAL = 0; - private static final int __LAST_WAS_CR = 1; - private static final int __LAST_WAS_NL = 2; - private int __status; - - /*** - * Creates a ToNetASCIIInputStream instance that wraps an existing - * InputStream. - * - * @param input The InputStream to wrap. - ***/ - public ToNetASCIIInputStream(InputStream input) { - super(input); - __status = __NOTHING_SPECIAL; - } - - /*** - * Reads and returns the next byte in the stream. If the end of the - * message has been reached, returns -1. - * - * @return The next character in the stream. Returns -1 if the end of the - * stream has been reached. - * @throws IOException If an error occurs while reading the underlying - * stream. - ***/ - @Override public int read() throws IOException { - int ch; - - if (__status == __LAST_WAS_NL) { - __status = __NOTHING_SPECIAL; - return '\n'; - } - - ch = in.read(); - - switch (ch) { - case '\r': - __status = __LAST_WAS_CR; - return '\r'; - case '\n': - if (__status != __LAST_WAS_CR) { - __status = __LAST_WAS_NL; - return '\r'; - } - //$FALL-THROUGH$ - default: - __status = __NOTHING_SPECIAL; - return ch; - } - // statement not reached - //return ch; - } - - /*** - * Reads the next number of bytes from the stream into an array and - * returns the number of bytes read. Returns -1 if the end of the - * stream has been reached. - * - * @param buffer The byte array in which to store the data. - * @return The number of bytes read. Returns -1 if the - * end of the message has been reached. - * @throws IOException If an error occurs in reading the underlying - * stream. - ***/ - @Override public int read(byte buffer[]) throws IOException { - return read(buffer, 0, buffer.length); - } - - /*** - * Reads the next number of bytes from the stream into an array and returns - * the number of bytes read. Returns -1 if the end of the - * message has been reached. The characters are stored in the array - * starting from the given offset and up to the length specified. - * - * @param buffer The byte array in which to store the data. - * @param offset The offset into the array at which to start storing data. - * @param length The number of bytes to read. - * @return The number of bytes read. Returns -1 if the - * end of the stream has been reached. - * @throws IOException If an error occurs while reading the underlying - * stream. - ***/ - @Override public int read(byte buffer[], int offset, int length) throws IOException { - int ch, off; - - if (length < 1) { - return 0; - } - - ch = available(); - - if (length > ch) { - length = ch; - } - - // If nothing is available, block to read only one character - if (length < 1) { - length = 1; - } - - if ((ch = read()) == -1) { - return -1; - } - - off = offset; - - do { - buffer[offset++] = (byte) ch; - } while (--length > 0 && (ch = read()) != -1); - - return (offset - off); - } - - /*** Returns false. Mark is not supported. ***/ - @Override public boolean markSupported() { - return false; - } - - @Override public int available() throws IOException { - int result; - - result = in.available(); - - if (__status == __LAST_WAS_NL) { - return (result + 1); - } - - return result; - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/ToNetASCIIOutputStream.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/ToNetASCIIOutputStream.java deleted file mode 100644 index d54a8758..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/ToNetASCIIOutputStream.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.io; - -import java.io.FilterOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/*** - * This class wraps an output stream, replacing all singly occurring - * <LF> (linefeed) characters with <CR><LF> (carriage return - * followed by linefeed), which is the NETASCII standard for representing - * a newline. - * You would use this class to implement ASCII file transfers requiring - * conversion to NETASCII. - * - * - ***/ - -public final class ToNetASCIIOutputStream extends FilterOutputStream { - private boolean __lastWasCR; - - /*** - * Creates a ToNetASCIIOutputStream instance that wraps an existing - * OutputStream. - * - * @param output The OutputStream to wrap. - ***/ - public ToNetASCIIOutputStream(OutputStream output) { - super(output); - __lastWasCR = false; - } - - /*** - * Writes a byte to the stream. Note that a call to this method - * may result in multiple writes to the underlying input stream in order - * to convert naked newlines to NETASCII line separators. - * This is transparent to the programmer and is only mentioned for - * completeness. - * - * @param ch The byte to write. - * @throws IOException If an error occurs while writing to the underlying - * stream. - ***/ - @Override public synchronized void write(int ch) throws IOException { - switch (ch) { - case '\r': - __lastWasCR = true; - out.write('\r'); - return; - case '\n': - if (!__lastWasCR) { - out.write('\r'); - } - //$FALL-THROUGH$ - default: - __lastWasCR = false; - out.write(ch); - return; - } - } - - /*** - * Writes a byte array to the stream. - * - * @param buffer The byte array to write. - * @throws IOException If an error occurs while writing to the underlying - * stream. - ***/ - @Override public synchronized void write(byte buffer[]) throws IOException { - write(buffer, 0, buffer.length); - } - - /*** - * Writes a number of bytes from a byte array to the stream starting from - * a given offset. - * - * @param buffer The byte array to write. - * @param offset The offset into the array at which to start copying data. - * @param length The number of bytes to write. - * @throws IOException If an error occurs while writing to the underlying - * stream. - ***/ - @Override public synchronized void write(byte buffer[], int offset, int length) - throws IOException { - while (length-- > 0) { - write(buffer[offset++]); - } - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/Util.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/Util.java deleted file mode 100644 index bdf74b76..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/Util.java +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.io; - -import java.io.Closeable; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Reader; -import java.io.Writer; -import java.net.Socket; - -/*** - * The Util class cannot be instantiated and stores short static convenience - * methods that are often quite useful. - * - * - * @see CopyStreamException - * @see CopyStreamListener - * @see CopyStreamAdapter - ***/ - -public final class Util { - /** - * The default buffer size ({@value}) used by - * {@link #copyStream copyStream } and {@link #copyReader copyReader} - * and by the copyReader/copyStream methods if a zero or negative buffer size is supplied. - */ - public static final int DEFAULT_COPY_BUFFER_SIZE = 1024; - - // Cannot be instantiated - private Util() { - } - - /*** - * Copies the contents of an InputStream to an OutputStream using a - * copy buffer of a given size and notifies the provided - * CopyStreamListener of the progress of the copy operation by calling - * its bytesTransferred(long, int) method after each write to the - * destination. If you wish to notify more than one listener you should - * use a CopyStreamAdapter as the listener and register the additional - * listeners with the CopyStreamAdapter. - *

- * The contents of the InputStream are - * read until the end of the stream is reached, but neither the - * source nor the destination are closed. You must do this yourself - * outside of the method call. The number of bytes read/written is - * returned. - * - * @param source The source InputStream. - * @param dest The destination OutputStream. - * @param bufferSize The number of bytes to buffer during the copy. - * A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. - * @param streamSize The number of bytes in the stream being copied. - * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. - * Not currently used (though it is passed to {@link CopyStreamListener#bytesTransferred(long, int, long)} - * @param listener The CopyStreamListener to notify of progress. If - * this parameter is null, notification is not attempted. - * @param flush Whether to flush the output stream after every - * write. This is necessary for interactive sessions that rely on - * buffered streams. If you don't flush, the data will stay in - * the stream buffer. - * @return number of bytes read/written - * @throws CopyStreamException If an error occurs while reading from the - * source or writing to the destination. The CopyStreamException - * will contain the number of bytes confirmed to have been - * transferred before an - * IOException occurred, and it will also contain the IOException - * that caused the error. These values can be retrieved with - * the CopyStreamException getTotalBytesTransferred() and - * getIOException() methods. - ***/ - public static final long copyStream(InputStream source, OutputStream dest, int bufferSize, - long streamSize, CopyStreamListener listener, boolean flush) throws CopyStreamException { - int numBytes; - long total = 0; - byte[] buffer = new byte[bufferSize > 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE]; - - try { - while (!Thread.currentThread().isInterrupted() && (numBytes = source.read(buffer)) != -1) { - // Technically, some read(byte[]) methods may return 0 and we cannot - // accept that as an indication of EOF. - - if (numBytes == 0) { - int singleByte = source.read(); - if (singleByte < 0) { - break; - } - dest.write(singleByte); - if (flush) { - dest.flush(); - } - ++total; - if (listener != null) { - listener.bytesTransferred(total, 1, streamSize); - } - continue; - } - - dest.write(buffer, 0, numBytes); - if (flush) { - dest.flush(); - } - total += numBytes; - if (listener != null) { - listener.bytesTransferred(total, numBytes, streamSize); - } - } - } catch (IOException e) { - throw new CopyStreamException("IOException caught while copying.", total, e); - } - - return total; - } - - - /*** - * Copies the contents of an InputStream to an OutputStream using a - * copy buffer of a given size and notifies the provided - * CopyStreamListener of the progress of the copy operation by calling - * its bytesTransferred(long, int) method after each write to the - * destination. If you wish to notify more than one listener you should - * use a CopyStreamAdapter as the listener and register the additional - * listeners with the CopyStreamAdapter. - *

- * The contents of the InputStream are - * read until the end of the stream is reached, but neither the - * source nor the destination are closed. You must do this yourself - * outside of the method call. The number of bytes read/written is - * returned. - * - * @param source The source InputStream. - * @param dest The destination OutputStream. - * @param bufferSize The number of bytes to buffer during the copy. - * A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. - * @param streamSize The number of bytes in the stream being copied. - * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. - * Not currently used (though it is passed to {@link CopyStreamListener#bytesTransferred(long, int, long)} - * @param listener The CopyStreamListener to notify of progress. If - * this parameter is null, notification is not attempted. - * @return number of bytes read/written - * @throws CopyStreamException If an error occurs while reading from the - * source or writing to the destination. The CopyStreamException - * will contain the number of bytes confirmed to have been - * transferred before an - * IOException occurred, and it will also contain the IOException - * that caused the error. These values can be retrieved with - * the CopyStreamException getTotalBytesTransferred() and - * getIOException() methods. - ***/ - public static final long copyStream(InputStream source, OutputStream dest, int bufferSize, - long streamSize, CopyStreamListener listener) throws CopyStreamException { - return copyStream(source, dest, bufferSize, streamSize, listener, true); - } - - /*** - * Copies the contents of an InputStream to an OutputStream using a - * copy buffer of a given size. The contents of the InputStream are - * read until the end of the stream is reached, but neither the - * source nor the destination are closed. You must do this yourself - * outside of the method call. The number of bytes read/written is - * returned. - * - * @param source The source InputStream. - * @param dest The destination OutputStream. - * @param bufferSize The number of bytes to buffer during the copy. - * A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. - * @return The number of bytes read/written in the copy operation. - * @throws CopyStreamException If an error occurs while reading from the - * source or writing to the destination. The CopyStreamException - * will contain the number of bytes confirmed to have been - * transferred before an - * IOException occurred, and it will also contain the IOException - * that caused the error. These values can be retrieved with - * the CopyStreamException getTotalBytesTransferred() and - * getIOException() methods. - ***/ - public static final long copyStream(InputStream source, OutputStream dest, int bufferSize) - throws CopyStreamException { - return copyStream(source, dest, bufferSize, CopyStreamEvent.UNKNOWN_STREAM_SIZE, null); - } - - /*** - * Same as copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); - * @param source where to copy from - * @param dest where to copy to - * @return number of bytes copied - * @throws CopyStreamException on error - ***/ - public static final long copyStream(InputStream source, OutputStream dest) - throws CopyStreamException { - return copyStream(source, dest, DEFAULT_COPY_BUFFER_SIZE); - } - - /*** - * Copies the contents of a Reader to a Writer using a - * copy buffer of a given size and notifies the provided - * CopyStreamListener of the progress of the copy operation by calling - * its bytesTransferred(long, int) method after each write to the - * destination. If you wish to notify more than one listener you should - * use a CopyStreamAdapter as the listener and register the additional - * listeners with the CopyStreamAdapter. - *

- * The contents of the Reader are - * read until its end is reached, but neither the source nor the - * destination are closed. You must do this yourself outside of the - * method call. The number of characters read/written is returned. - * - * @param source The source Reader. - * @param dest The destination writer. - * @param bufferSize The number of characters to buffer during the copy. - * A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. - * @param streamSize The number of characters in the stream being copied. - * Should be set to CopyStreamEvent.UNKNOWN_STREAM_SIZE if unknown. - * Not currently used (though it is passed to {@link CopyStreamListener#bytesTransferred(long, int, long)} - * @param listener The CopyStreamListener to notify of progress. If - * this parameter is null, notification is not attempted. - * @return The number of characters read/written in the copy operation. - * @throws CopyStreamException If an error occurs while reading from the - * source or writing to the destination. The CopyStreamException - * will contain the number of bytes confirmed to have been - * transferred before an - * IOException occurred, and it will also contain the IOException - * that caused the error. These values can be retrieved with - * the CopyStreamException getTotalBytesTransferred() and - * getIOException() methods. - ***/ - public static final long copyReader(Reader source, Writer dest, int bufferSize, long streamSize, - CopyStreamListener listener) throws CopyStreamException { - int numChars; - long total = 0; - char[] buffer = new char[bufferSize > 0 ? bufferSize : DEFAULT_COPY_BUFFER_SIZE]; - - try { - while ((numChars = source.read(buffer)) != -1) { - // Technically, some read(char[]) methods may return 0 and we cannot - // accept that as an indication of EOF. - if (numChars == 0) { - int singleChar = source.read(); - if (singleChar < 0) { - break; - } - dest.write(singleChar); - dest.flush(); - ++total; - if (listener != null) { - listener.bytesTransferred(total, 1, streamSize); - } - continue; - } - - dest.write(buffer, 0, numChars); - dest.flush(); - total += numChars; - if (listener != null) { - listener.bytesTransferred(total, numChars, streamSize); - } - } - } catch (IOException e) { - throw new CopyStreamException("IOException caught while copying.", total, e); - } - - return total; - } - - /*** - * Copies the contents of a Reader to a Writer using a - * copy buffer of a given size. The contents of the Reader are - * read until its end is reached, but neither the source nor the - * destination are closed. You must do this yourself outside of the - * method call. The number of characters read/written is returned. - * - * @param source The source Reader. - * @param dest The destination writer. - * @param bufferSize The number of characters to buffer during the copy. - * A zero or negative value means to use {@link #DEFAULT_COPY_BUFFER_SIZE}. - * @return The number of characters read/written in the copy operation. - * @throws CopyStreamException If an error occurs while reading from the - * source or writing to the destination. The CopyStreamException - * will contain the number of bytes confirmed to have been - * transferred before an - * IOException occurred, and it will also contain the IOException - * that caused the error. These values can be retrieved with - * the CopyStreamException getTotalBytesTransferred() and - * getIOException() methods. - ***/ - public static final long copyReader(Reader source, Writer dest, int bufferSize) - throws CopyStreamException { - return copyReader(source, dest, bufferSize, CopyStreamEvent.UNKNOWN_STREAM_SIZE, null); - } - - /*** - * Same as copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); - * @param source where to copy from - * @param dest where to copy to - * @return number of bytes copied - * @throws CopyStreamException on error - ***/ - public static final long copyReader(Reader source, Writer dest) throws CopyStreamException { - return copyReader(source, dest, DEFAULT_COPY_BUFFER_SIZE); - } - - /** - * Closes the object quietly, catching rather than throwing IOException. - * Intended for use from finally blocks. - * - * @param closeable the object to close, may be {@code null} - * @since 3.0 - */ - public static void closeQuietly(Closeable closeable) { - if (closeable != null) { - try { - closeable.close(); - } catch (IOException e) { - // Ignored - } - } - } - - /** - * Closes the socket quietly, catching rather than throwing IOException. - * Intended for use from finally blocks. - * - * @param socket the socket to close, may be {@code null} - * @since 3.0 - */ - public static void closeQuietly(Socket socket) { - if (socket != null) { - try { - socket.close(); - } catch (IOException e) { - // Ignored - } - } - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/package-info.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/package-info.java deleted file mode 100644 index 06207d12..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/io/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -/** - * Utility classes for IO support. - */ -package aria.apache.commons.net.io; \ No newline at end of file diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/Base64.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/Base64.java deleted file mode 100644 index a03150e0..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/Base64.java +++ /dev/null @@ -1,1056 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.util; - -import java.io.UnsupportedEncodingException; -import java.math.BigInteger; - -/** - * Provides Base64 encoding and decoding as defined by RFC 2045. - * - *

- * This class implements section 6.8. Base64 Content-Transfer-Encoding from RFC 2045 - * Multipurpose - * Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies by Freed and - * Borenstein. - *

- *

- * The class can be parameterized in the following manner with various constructors: - *

    - *
  • URL-safe mode: Default off.
  • - *
  • Line length: Default 76. Line length that aren't multiples of 4 will still essentially end up - * being multiples of - * 4 in the encoded data. - *
  • Line separator: Default is CRLF ("\r\n")
  • - *
- *

- * Since this class operates directly on byte streams, and not character streams, it is hard-coded - * to only encode/decode - * character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1, - * Windows-1252, UTF-8, etc). - *

- * - * @version $Id: Base64.java 1697293 2015-08-24 01:01:00Z sebb $ - * @see RFC 2045 - * @since 2.2 - */ -public class Base64 { - private static final int DEFAULT_BUFFER_RESIZE_FACTOR = 2; - - private static final int DEFAULT_BUFFER_SIZE = 8192; - - /** - * Chunk size per RFC 2045 section 6.8. - * - *

- * The {@value} character limit does not count the trailing CRLF, but counts all other characters, - * including any - * equal signs. - *

- * - * @see RFC 2045 section 6.8 - */ - static final int CHUNK_SIZE = 76; - - /** - * Chunk separator per RFC 2045 section 2.1. - * - * @see RFC 2045 section 2.1 - */ - private static final byte[] CHUNK_SEPARATOR = { '\r', '\n' }; - - private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; - - /** - * This array is a lookup table that translates 6-bit positive integer index values into their - * "Base64 Alphabet" - * equivalents as specified in Table 1 of RFC 2045. - * - * Thanks to "commons" project in ws.apache.org for this code. - * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ - */ - private static final byte[] STANDARD_ENCODE_TABLE = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', - 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', - '5', '6', '7', '8', '9', '+', '/' - }; - - /** - * This is a copy of the STANDARD_ENCODE_TABLE above, but with + and / - * changed to - and _ to make the encoded Base64 results more URL-SAFE. - * This table is only used when the Base64's mode is set to URL-SAFE. - */ - private static final byte[] URL_SAFE_ENCODE_TABLE = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', - 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', - 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', - '5', '6', '7', '8', '9', '-', '_' - }; - - /** - * Byte used to pad output. - */ - private static final byte PAD = '='; - - /** - * This array is a lookup table that translates Unicode characters drawn from the "Base64 - * Alphabet" (as specified in - * Table 1 of RFC 2045) into their 6-bit positive integer equivalents. Characters that are not in - * the Base64 - * alphabet but fall within the bounds of the array are translated to -1. - * - * Note: '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder - * seamlessly handles both - * URL_SAFE and STANDARD base64. (The encoder, on the other hand, needs to know ahead of time what - * to emit). - * - * Thanks to "commons" project in ws.apache.org for this code. - * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ - */ - private static final byte[] DECODE_TABLE = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, - -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, - 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51 - }; - - /** Mask used to extract 6 bits, used when encoding */ - private static final int MASK_6BITS = 0x3f; - - /** Mask used to extract 8 bits, used in decoding base64 bytes */ - private static final int MASK_8BITS = 0xff; - - // The static final fields above are used for the original static byte[] methods on Base64. - // The private member fields below are used with the new streaming approach, which requires - // some state be preserved between calls of encode() and decode(). - - /** - * Encode table to use: either STANDARD or URL_SAFE. Note: the DECODE_TABLE above remains static - * because it is able - * to decode both STANDARD and URL_SAFE streams, but the encodeTable must be a member variable so - * we can switch - * between the two modes. - */ - private final byte[] encodeTable; - - /** - * Line length for encoding. Not used when decoding. A value of zero or less implies no chunking - * of the base64 - * encoded data. - */ - private final int lineLength; - - /** - * Line separator for encoding. Not used when decoding. Only used if lineLength > 0. - */ - private final byte[] lineSeparator; - - /** - * Convenience variable to help us determine when our buffer is going to run out of room and needs - * resizing. - * decodeSize = 3 + lineSeparator.length; - */ - private final int decodeSize; - - /** - * Convenience variable to help us determine when our buffer is going to run out of room and needs - * resizing. - * encodeSize = 4 + lineSeparator.length; - */ - private final int encodeSize; - - /** - * Buffer for streaming. - */ - private byte[] buffer; - - /** - * Position where next character should be written in the buffer. - */ - private int pos; - - /** - * Position where next character should be read from the buffer. - */ - private int readPos; - - /** - * Variable tracks how many characters have been written to the current line. Only used when - * encoding. We use it to - * make sure each encoded line never goes beyond lineLength (if lineLength > 0). - */ - private int currentLinePos; - - /** - * Writes to the buffer only occur after every 3 reads when encoding, an every 4 reads when - * decoding. This variable - * helps track that. - */ - private int modulus; - - /** - * Boolean flag to indicate the EOF has been reached. Once EOF has been reached, this Base64 - * object becomes useless, - * and must be thrown away. - */ - private boolean eof; - - /** - * Place holder for the 3 bytes we're dealing with for our base64 logic. Bitwise operations store - * and extract the - * base64 encoding or decoding from this variable. - */ - private int x; - - /** - * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. - *

- * When encoding the line length is 76, the line separator is CRLF, and the encoding table is - * STANDARD_ENCODE_TABLE. - *

- * - *

- * When decoding all variants are supported. - *

- */ - public Base64() { - this(false); - } - - /** - * Creates a Base64 codec used for decoding (all modes) and encoding in the given URL-safe mode. - *

- * When encoding the line length is 76, the line separator is CRLF, and the encoding table is - * STANDARD_ENCODE_TABLE. - *

- * - *

- * When decoding all variants are supported. - *

- * - * @param urlSafe if true, URL-safe encoding is used. In most cases this should be - * set to - * false. - * @since 1.4 - */ - public Base64(boolean urlSafe) { - this(CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe); - } - - /** - * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. - *

- * When encoding the line length is given in the constructor, the line separator is CRLF, and the - * encoding table is - * STANDARD_ENCODE_TABLE. - *

- *

- * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in - * the encoded data. - *

- *

- * When decoding all variants are supported. - *

- * - * @param lineLength Each line of encoded data will be at most of the given length (rounded down - * to nearest multiple of 4). - * If {@code lineLength <= 0}, then the output will not be divided into lines (chunks). Ignored - * when decoding. - * @since 1.4 - */ - public Base64(int lineLength) { - this(lineLength, CHUNK_SEPARATOR); - } - - /** - * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. - *

- * When encoding the line length and line separator are given in the constructor, and the encoding - * table is - * STANDARD_ENCODE_TABLE. - *

- *

- * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in - * the encoded data. - *

- *

- * When decoding all variants are supported. - *

- * - * @param lineLength Each line of encoded data will be at most of the given length (rounded down - * to nearest multiple of 4). - * If {@code lineLength <= 0}, then the output will not be divided into lines (chunks). Ignored - * when decoding. - * @param lineSeparator Each line of encoded data will end with this sequence of bytes. - * @throws IllegalArgumentException Thrown when the provided lineSeparator included some base64 - * characters. - * @since 1.4 - */ - public Base64(int lineLength, byte[] lineSeparator) { - this(lineLength, lineSeparator, false); - } - - /** - * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. - *

- * When encoding the line length and line separator are given in the constructor, and the encoding - * table is - * STANDARD_ENCODE_TABLE. - *

- *

- * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in - * the encoded data. - *

- *

- * When decoding all variants are supported. - *

- * - * @param lineLength Each line of encoded data will be at most of the given length (rounded down - * to nearest multiple of 4). - * If {@code lineLength <= 0}, then the output will not be divided into lines (chunks). Ignored - * when decoding. - * @param lineSeparator Each line of encoded data will end with this sequence of bytes. - * @param urlSafe Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is - * only applied to encode - * operations. Decoding seamlessly handles both modes. - * @throws IllegalArgumentException The provided lineSeparator included some base64 characters. - * That's not going to work! - * @since 1.4 - */ - public Base64(int lineLength, byte[] lineSeparator, boolean urlSafe) { - if (lineSeparator == null) { - lineLength = 0; // disable chunk-separating - lineSeparator = EMPTY_BYTE_ARRAY; // this just gets ignored - } - this.lineLength = lineLength > 0 ? (lineLength / 4) * 4 : 0; - this.lineSeparator = new byte[lineSeparator.length]; - System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length); - if (lineLength > 0) { - this.encodeSize = 4 + lineSeparator.length; - } else { - this.encodeSize = 4; - } - this.decodeSize = this.encodeSize - 1; - if (containsBase64Byte(lineSeparator)) { - String sep = newStringUtf8(lineSeparator); - throw new IllegalArgumentException( - "lineSeperator must not contain base64 characters: [" + sep + "]"); - } - this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE; - } - - /** - * Returns our current encode mode. True if we're URL-SAFE, false otherwise. - * - * @return true if we're in URL-SAFE mode, false otherwise. - * @since 1.4 - */ - public boolean isUrlSafe() { - return this.encodeTable == URL_SAFE_ENCODE_TABLE; - } - - /** - * Returns true if this Base64 object has buffered data for reading. - * - * @return true if there is Base64 object still available for reading. - */ - boolean hasData() { - return this.buffer != null; - } - - /** - * Returns the amount of buffered data available for reading. - * - * @return The amount of buffered data available for reading. - */ - int avail() { - return buffer != null ? pos - readPos : 0; - } - - /** Doubles our buffer. */ - private void resizeBuffer() { - if (buffer == null) { - buffer = new byte[DEFAULT_BUFFER_SIZE]; - pos = 0; - readPos = 0; - } else { - byte[] b = new byte[buffer.length * DEFAULT_BUFFER_RESIZE_FACTOR]; - System.arraycopy(buffer, 0, b, 0, buffer.length); - buffer = b; - } - } - - /** - * Extracts buffered data into the provided byte[] array, starting at position bPos, up to a - * maximum of bAvail - * bytes. Returns how many bytes were actually extracted. - * - * @param b byte[] array to extract the buffered data into. - * @param bPos position in byte[] array to start extraction at. - * @param bAvail amount of bytes we're allowed to extract. We may extract fewer (if fewer are - * available). - * @return The number of bytes successfully extracted into the provided byte[] array. - */ - int readResults(byte[] b, int bPos, int bAvail) { - if (buffer != null) { - int len = Math.min(avail(), bAvail); - if (buffer != b) { - System.arraycopy(buffer, readPos, b, bPos, len); - readPos += len; - if (readPos >= pos) { - buffer = null; - } - } else { - // Re-using the original consumer's output array is only - // allowed for one round. - buffer = null; - } - return len; - } - return eof ? -1 : 0; - } - - /** - * Sets the streaming buffer. This is a small optimization where we try to buffer directly to the - * consumer's output - * array for one round (if the consumer calls this method first) instead of starting our own - * buffer. - * - * @param out byte[] array to buffer directly to. - * @param outPos Position to start buffering into. - * @param outAvail Amount of bytes available for direct buffering. - */ - void setInitialBuffer(byte[] out, int outPos, int outAvail) { - // We can re-use consumer's original output array under - // special circumstances, saving on some System.arraycopy(). - if (out != null && out.length == outAvail) { - buffer = out; - pos = outPos; - readPos = outPos; - } - } - - /** - *

- * Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least - * twice: once with - * the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been - * reached, so flush last - * remaining bytes (if not multiple of 3). - *

- *

- * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach. - * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ - *

- * - * @param in byte[] array of binary data to base64 encode. - * @param inPos Position to start reading data from. - * @param inAvail Amount of bytes available from input for encoding. - */ - void encode(byte[] in, int inPos, int inAvail) { - if (eof) { - return; - } - // inAvail < 0 is how we're informed of EOF in the underlying data we're - // encoding. - if (inAvail < 0) { - eof = true; - if (buffer == null || buffer.length - pos < encodeSize) { - resizeBuffer(); - } - switch (modulus) { - case 1: - buffer[pos++] = encodeTable[(x >> 2) & MASK_6BITS]; - buffer[pos++] = encodeTable[(x << 4) & MASK_6BITS]; - // URL-SAFE skips the padding to further reduce size. - if (encodeTable == STANDARD_ENCODE_TABLE) { - buffer[pos++] = PAD; - buffer[pos++] = PAD; - } - break; - - case 2: - buffer[pos++] = encodeTable[(x >> 10) & MASK_6BITS]; - buffer[pos++] = encodeTable[(x >> 4) & MASK_6BITS]; - buffer[pos++] = encodeTable[(x << 2) & MASK_6BITS]; - // URL-SAFE skips the padding to further reduce size. - if (encodeTable == STANDARD_ENCODE_TABLE) { - buffer[pos++] = PAD; - } - break; - default: - break; // other values ignored - } - if (lineLength > 0 && pos > 0) { - System.arraycopy(lineSeparator, 0, buffer, pos, lineSeparator.length); - pos += lineSeparator.length; - } - } else { - for (int i = 0; i < inAvail; i++) { - if (buffer == null || buffer.length - pos < encodeSize) { - resizeBuffer(); - } - modulus = (++modulus) % 3; - int b = in[inPos++]; - if (b < 0) { - b += 256; - } - x = (x << 8) + b; - if (0 == modulus) { - buffer[pos++] = encodeTable[(x >> 18) & MASK_6BITS]; - buffer[pos++] = encodeTable[(x >> 12) & MASK_6BITS]; - buffer[pos++] = encodeTable[(x >> 6) & MASK_6BITS]; - buffer[pos++] = encodeTable[x & MASK_6BITS]; - currentLinePos += 4; - if (lineLength > 0 && lineLength <= currentLinePos) { - System.arraycopy(lineSeparator, 0, buffer, pos, lineSeparator.length); - pos += lineSeparator.length; - currentLinePos = 0; - } - } - } - } - } - - /** - *

- * Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at - * least twice: once - * with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been - * reached. The "-1" - * call is not necessary when decoding, but it doesn't hurt, either. - *

- *

- * Ignores all non-base64 characters. This is how chunked (e.g. 76 character) data is handled, - * since CR and LF are - * silently ignored, but has implications for other bytes, too. This method subscribes to the - * garbage-in, - * garbage-out philosophy: it will not check the provided data for validity. - *

- *

- * Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach. - * http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/ - *

- * - * @param in byte[] array of ascii data to base64 decode. - * @param inPos Position to start reading data from. - * @param inAvail Amount of bytes available from input for encoding. - */ - void decode(byte[] in, int inPos, int inAvail) { - if (eof) { - return; - } - if (inAvail < 0) { - eof = true; - } - for (int i = 0; i < inAvail; i++) { - if (buffer == null || buffer.length - pos < decodeSize) { - resizeBuffer(); - } - byte b = in[inPos++]; - if (b == PAD) { - // We're done. - eof = true; - break; - } else { - if (b >= 0 && b < DECODE_TABLE.length) { - int result = DECODE_TABLE[b]; - if (result >= 0) { - modulus = (++modulus) % 4; - x = (x << 6) + result; - if (modulus == 0) { - buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS); - buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS); - buffer[pos++] = (byte) (x & MASK_8BITS); - } - } - } - } - } - - // Two forms of EOF as far as base64 decoder is concerned: actual - // EOF (-1) and first time '=' character is encountered in stream. - // This approach makes the '=' padding characters completely optional. - if (eof && modulus != 0) { - x = x << 6; - switch (modulus) { - case 2: - x = x << 6; - buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS); - break; - case 3: - buffer[pos++] = (byte) ((x >> 16) & MASK_8BITS); - buffer[pos++] = (byte) ((x >> 8) & MASK_8BITS); - break; - default: - break; // other values ignored - } - } - } - - /** - * Returns whether or not the octet is in the base 64 alphabet. - * - * @param octet The value to test - * @return true if the value is defined in the the base 64 alphabet, - * false otherwise. - * @since 1.4 - */ - public static boolean isBase64(byte octet) { - return octet == PAD || (octet >= 0 && octet < DECODE_TABLE.length && DECODE_TABLE[octet] != -1); - } - - /** - * Tests a given byte array to see if it contains only valid characters within the Base64 - * alphabet. Currently the - * method treats whitespace as valid. - * - * @param arrayOctet byte array to test - * @return true if all bytes are valid characters in the Base64 alphabet or if the - * byte array is empty; - * false, otherwise - */ - public static boolean isArrayByteBase64(byte[] arrayOctet) { - for (int i = 0; i < arrayOctet.length; i++) { - if (!isBase64(arrayOctet[i]) && !isWhiteSpace(arrayOctet[i])) { - return false; - } - } - return true; - } - - /** - * Tests a given byte array to see if it contains only valid characters within the Base64 - * alphabet. - * - * @param arrayOctet byte array to test - * @return true if any byte is a valid character in the Base64 alphabet; false - * herwise - */ - private static boolean containsBase64Byte(byte[] arrayOctet) { - for (byte element : arrayOctet) { - if (isBase64(element)) { - return true; - } - } - return false; - } - - /** - * Encodes binary data using the base64 algorithm but does not chunk the output. - * - * @param binaryData binary data to encode - * @return byte[] containing Base64 characters in their UTF-8 representation. - */ - public static byte[] encodeBase64(byte[] binaryData) { - return encodeBase64(binaryData, false); - } - - /** - * Encodes binary data using the base64 algorithm into 76 character blocks separated by CRLF. - *

- * For a non-chunking version, see {@link #encodeBase64StringUnChunked(byte[])}. - * - * @param binaryData binary data to encode - * @return String containing Base64 characters. - * @since 1.4 - */ - public static String encodeBase64String(byte[] binaryData) { - return newStringUtf8(encodeBase64(binaryData, true)); - } - - /** - * Encodes binary data using the base64 algorithm, without using chunking. - *

- * For a chunking version, see {@link #encodeBase64String(byte[])}. - * - * @param binaryData binary data to encode - * @return String containing Base64 characters. - * @since 3.2 - */ - public static String encodeBase64StringUnChunked(byte[] binaryData) { - return newStringUtf8(encodeBase64(binaryData, false)); - } - - /** - * Encodes binary data using the base64 algorithm. - * - * @param binaryData binary data to encode - * @param useChunking whether to split the output into chunks - * @return String containing Base64 characters. - * @since 3.2 - */ - public static String encodeBase64String(byte[] binaryData, boolean useChunking) { - return newStringUtf8(encodeBase64(binaryData, useChunking)); - } - - /** - * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the - * output. The - * url-safe variation emits - and _ instead of + and / characters. - * - * @param binaryData binary data to encode - * @return byte[] containing Base64 characters in their UTF-8 representation. - * @since 1.4 - */ - public static byte[] encodeBase64URLSafe(byte[] binaryData) { - return encodeBase64(binaryData, false, true); - } - - /** - * Encodes binary data using a URL-safe variation of the base64 algorithm but does not chunk the - * output. The - * url-safe variation emits - and _ instead of + and / characters. - * - * @param binaryData binary data to encode - * @return String containing Base64 characters - * @since 1.4 - */ - public static String encodeBase64URLSafeString(byte[] binaryData) { - return newStringUtf8(encodeBase64(binaryData, false, true)); - } - - /** - * Encodes binary data using the base64 algorithm and chunks the encoded output into 76 character - * blocks - * - * @param binaryData binary data to encode - * @return Base64 characters chunked in 76 character blocks - */ - public static byte[] encodeBase64Chunked(byte[] binaryData) { - return encodeBase64(binaryData, true); - } - - /** - * Decodes a String containing containing characters in the Base64 alphabet. - * - * @param pArray A String containing Base64 character data - * @return a byte array containing binary data - * @since 1.4 - */ - public byte[] decode(String pArray) { - return decode(getBytesUtf8(pArray)); - } - - private byte[] getBytesUtf8(String pArray) { - try { - return pArray.getBytes("UTF8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - - /** - * Decodes a byte[] containing containing characters in the Base64 alphabet. - * - * @param pArray A byte array containing Base64 character data - * @return a byte array containing binary data - */ - public byte[] decode(byte[] pArray) { - reset(); - if (pArray == null || pArray.length == 0) { - return pArray; - } - long len = (pArray.length * 3) / 4; - byte[] buf = new byte[(int) len]; - setInitialBuffer(buf, 0, buf.length); - decode(pArray, 0, pArray.length); - decode(pArray, 0, -1); // Notify decoder of EOF. - - // Would be nice to just return buf (like we sometimes do in the encode - // logic), but we have no idea what the line-length was (could even be - // variable). So we cannot determine ahead of time exactly how big an - // array is necessary. Hence the need to construct a 2nd byte array to - // hold the final result: - - byte[] result = new byte[pos]; - readResults(result, 0, result.length); - return result; - } - - /** - * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 - * character blocks. - * - * @param binaryData Array containing binary data to encode. - * @param isChunked if true this encoder will chunk the base64 output into 76 - * character blocks - * @return Base64-encoded data. - * @throws IllegalArgumentException Thrown when the input array needs an output array bigger than - * {@link Integer#MAX_VALUE} - */ - public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) { - return encodeBase64(binaryData, isChunked, false); - } - - /** - * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 - * character blocks. - * - * @param binaryData Array containing binary data to encode. - * @param isChunked if true this encoder will chunk the base64 output into 76 - * character blocks - * @param urlSafe if true this encoder will emit - and _ instead of the usual + and / - * characters. - * @return Base64-encoded data. - * @throws IllegalArgumentException Thrown when the input array needs an output array bigger than - * {@link Integer#MAX_VALUE} - * @since 1.4 - */ - public static byte[] encodeBase64(byte[] binaryData, boolean isChunked, boolean urlSafe) { - return encodeBase64(binaryData, isChunked, urlSafe, Integer.MAX_VALUE); - } - - /** - * Encodes binary data using the base64 algorithm, optionally chunking the output into 76 - * character blocks. - * - * @param binaryData Array containing binary data to encode. - * @param isChunked if true this encoder will chunk the base64 output into 76 - * character blocks - * @param urlSafe if true this encoder will emit - and _ instead of the usual + and / - * characters. - * @param maxResultSize The maximum result size to accept. - * @return Base64-encoded data. - * @throws IllegalArgumentException Thrown when the input array needs an output array bigger than - * maxResultSize - * @since 1.4 - */ - public static byte[] encodeBase64(byte[] binaryData, boolean isChunked, boolean urlSafe, - int maxResultSize) { - if (binaryData == null || binaryData.length == 0) { - return binaryData; - } - - long len = getEncodeLength(binaryData, isChunked ? CHUNK_SIZE : 0, - isChunked ? CHUNK_SEPARATOR : EMPTY_BYTE_ARRAY); - if (len > maxResultSize) { - throw new IllegalArgumentException("Input array too big, the output array would be bigger (" - + len - + ") than the specified maxium size of " - + maxResultSize); - } - - Base64 b64 = isChunked ? new Base64(urlSafe) : new Base64(0, CHUNK_SEPARATOR, urlSafe); - return b64.encode(binaryData); - } - - /** - * Decodes a Base64 String into octets - * - * @param base64String String containing Base64 data - * @return Array containing decoded data. - * @since 1.4 - */ - public static byte[] decodeBase64(String base64String) { - return new Base64().decode(base64String); - } - - /** - * Decodes Base64 data into octets - * - * @param base64Data Byte array containing Base64 data - * @return Array containing decoded data. - */ - public static byte[] decodeBase64(byte[] base64Data) { - return new Base64().decode(base64Data); - } - - /** - * Checks if a byte value is whitespace or not. - * - * @param byteToCheck the byte to check - * @return true if byte is whitespace, false otherwise - */ - private static boolean isWhiteSpace(byte byteToCheck) { - switch (byteToCheck) { - case ' ': - case '\n': - case '\r': - case '\t': - return true; - default: - return false; - } - } - - /** - * Encodes a byte[] containing binary data, into a String containing characters in the Base64 - * alphabet. - * - * @param pArray a byte array containing binary data - * @return A String containing only Base64 character data - * @since 1.4 - */ - public String encodeToString(byte[] pArray) { - return newStringUtf8(encode(pArray)); - } - - private static String newStringUtf8(byte[] encode) { - String str = null; - try { - str = new String(encode, "UTF8"); - } catch (UnsupportedEncodingException ue) { - throw new RuntimeException(ue); - } - return str; - } - - /** - * Encodes a byte[] containing binary data, into a byte[] containing characters in the Base64 - * alphabet. - * - * @param pArray a byte array containing binary data - * @return A byte array containing only Base64 character data - */ - public byte[] encode(byte[] pArray) { - reset(); - if (pArray == null || pArray.length == 0) { - return pArray; - } - long len = getEncodeLength(pArray, lineLength, lineSeparator); - byte[] buf = new byte[(int) len]; - setInitialBuffer(buf, 0, buf.length); - encode(pArray, 0, pArray.length); - encode(pArray, 0, -1); // Notify encoder of EOF. - // Encoder might have resized, even though it was unnecessary. - if (buffer != buf) { - readResults(buf, 0, buf.length); - } - // In URL-SAFE mode we skip the padding characters, so sometimes our - // final length is a bit smaller. - if (isUrlSafe() && pos < buf.length) { - byte[] smallerBuf = new byte[pos]; - System.arraycopy(buf, 0, smallerBuf, 0, pos); - buf = smallerBuf; - } - return buf; - } - - /** - * Pre-calculates the amount of space needed to base64-encode the supplied array. - * - * @param pArray byte[] array which will later be encoded - * @param chunkSize line-length of the output (<= 0 means no chunking) between each - * chunkSeparator (e.g. CRLF). - * @param chunkSeparator the sequence of bytes used to separate chunks of output (e.g. CRLF). - * @return amount of space needed to encoded the supplied array. Returns - * a long since a max-len array will require Integer.MAX_VALUE + 33%. - */ - private static long getEncodeLength(byte[] pArray, int chunkSize, byte[] chunkSeparator) { - // base64 always encodes to multiples of 4. - chunkSize = (chunkSize / 4) * 4; - - long len = (pArray.length * 4) / 3; - long mod = len % 4; - if (mod != 0) { - len += 4 - mod; - } - if (chunkSize > 0) { - boolean lenChunksPerfectly = len % chunkSize == 0; - len += (len / chunkSize) * chunkSeparator.length; - if (!lenChunksPerfectly) { - len += chunkSeparator.length; - } - } - return len; - } - - // Implementation of integer encoding used for crypto - - /** - * Decodes a byte64-encoded integer according to crypto standards such as W3C's XML-Signature - * - * @param pArray a byte array containing base64 character data - * @return A BigInteger - * @since 1.4 - */ - public static BigInteger decodeInteger(byte[] pArray) { - return new BigInteger(1, decodeBase64(pArray)); - } - - /** - * Encodes to a byte64-encoded integer according to crypto standards such as W3C's XML-Signature - * - * @param bigInt a BigInteger - * @return A byte array containing base64 character data - * @throws NullPointerException if null is passed in - * @since 1.4 - */ - public static byte[] encodeInteger(BigInteger bigInt) { - if (bigInt == null) { - throw new NullPointerException("encodeInteger called with null parameter"); - } - return encodeBase64(toIntegerBytes(bigInt), false); - } - - /** - * Returns a byte-array representation of a BigInteger without sign bit. - * - * @param bigInt BigInteger to be converted - * @return a byte array representation of the BigInteger parameter - */ - static byte[] toIntegerBytes(BigInteger bigInt) { - int bitlen = bigInt.bitLength(); - // round bitlen - bitlen = ((bitlen + 7) >> 3) << 3; - byte[] bigBytes = bigInt.toByteArray(); - - if (((bigInt.bitLength() % 8) != 0) && (((bigInt.bitLength() / 8) + 1) == (bitlen / 8))) { - return bigBytes; - } - // set up params for copying everything but sign bit - int startSrc = 0; - int len = bigBytes.length; - - // if bigInt is exactly byte-aligned, just skip signbit in copy - if ((bigInt.bitLength() % 8) == 0) { - startSrc = 1; - len--; - } - int startDst = bitlen / 8 - len; // to pad w/ nulls as per spec - byte[] resizedBytes = new byte[bitlen / 8]; - System.arraycopy(bigBytes, startSrc, resizedBytes, startDst, len); - return resizedBytes; - } - - /** - * Resets this Base64 object to its initial newly constructed state. - */ - private void reset() { - buffer = null; - pos = 0; - readPos = 0; - currentLinePos = 0; - modulus = 0; - eof = false; - } - - // Getters for use in testing - - int getLineLength() { - return lineLength; - } - - byte[] getLineSeparator() { - return lineSeparator.clone(); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/Charsets.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/Charsets.java deleted file mode 100644 index 5001fcc0..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/Charsets.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.util; - -import java.nio.charset.Charset; - -/** - * Helps dealing with Charsets. - * - * @since 3.3 - */ -public class Charsets { - - /** - * Returns a charset object for the given charset name. - * - * @param charsetName The name of the requested charset; may be a canonical name, an alias, or - * null. If null, return the - * default charset. - * @return A charset object for the named charset - */ - public static Charset toCharset(String charsetName) { - return charsetName == null ? Charset.defaultCharset() : Charset.forName(charsetName); - } - - /** - * Returns a charset object for the given charset name. - * - * @param charsetName The name of the requested charset; may be a canonical name, an alias, or - * null. - * If null, return the default charset. - * @param defaultCharsetName the charset name to use if the requested charset is null - * @return A charset object for the named charset - */ - public static Charset toCharset(String charsetName, String defaultCharsetName) { - return charsetName == null ? Charset.forName(defaultCharsetName) : Charset.forName(charsetName); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/KeyManagerUtils.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/KeyManagerUtils.java deleted file mode 100644 index 012493b0..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/KeyManagerUtils.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.util; - -import aria.apache.commons.net.io.Util; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.net.Socket; -import java.security.GeneralSecurityException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.Principal; -import java.security.PrivateKey; -import java.security.cert.Certificate; -import java.security.cert.X509Certificate; -import java.util.Enumeration; - -import javax.net.ssl.KeyManager; -import javax.net.ssl.X509ExtendedKeyManager; - -/** - * General KeyManager utilities - *

- * How to use with a client certificate: - *

- * KeyManager km = KeyManagerUtils.createClientKeyManager("JKS",
- *     "/path/to/privatekeystore.jks","storepassword",
- *     "privatekeyalias", "keypassword");
- * FTPSClient cl = new FTPSClient();
- * cl.setKeyManager(km);
- * cl.connect(...);
- * 
- * If using the default store type and the key password is the same as the - * store password, these parameters can be omitted.
- * If the desired key is the first or only key in the keystore, the keyAlias parameter - * can be omitted, in which case the code becomes: - *
- * KeyManager km = KeyManagerUtils.createClientKeyManager(
- *     "/path/to/privatekeystore.jks","storepassword");
- * FTPSClient cl = new FTPSClient();
- * cl.setKeyManager(km);
- * cl.connect(...);
- * 
- * - * @since 3.0 - */ -public final class KeyManagerUtils { - - private static final String DEFAULT_STORE_TYPE = KeyStore.getDefaultType(); - - private KeyManagerUtils() { - // Not instantiable - } - - /** - * Create a client key manager which returns a particular key. - * Does not handle server keys. - * - * @param ks the keystore to use - * @param keyAlias the alias of the key to use, may be {@code null} in which case the first key - * entry alias is used - * @param keyPass the password of the key to use - * @return the customised KeyManager - * @throws GeneralSecurityException if there is a problem creating the keystore - */ - public static KeyManager createClientKeyManager(KeyStore ks, String keyAlias, String keyPass) - throws GeneralSecurityException { - ClientKeyStore cks = - new ClientKeyStore(ks, keyAlias != null ? keyAlias : findAlias(ks), keyPass); - return new X509KeyManager(cks); - } - - /** - * Create a client key manager which returns a particular key. - * Does not handle server keys. - * - * @param storeType the type of the keyStore, e.g. "JKS" - * @param storePath the path to the keyStore - * @param storePass the keyStore password - * @param keyAlias the alias of the key to use, may be {@code null} in which case the first key - * entry alias is used - * @param keyPass the password of the key to use - * @return the customised KeyManager - * @throws GeneralSecurityException if there is a problem creating the keystore - * @throws IOException if there is a problem creating the keystore - */ - public static KeyManager createClientKeyManager(String storeType, File storePath, - String storePass, String keyAlias, String keyPass) - throws IOException, GeneralSecurityException { - KeyStore ks = loadStore(storeType, storePath, storePass); - return createClientKeyManager(ks, keyAlias, keyPass); - } - - /** - * Create a client key manager which returns a particular key. - * Does not handle server keys. - * Uses the default store type and assumes the key password is the same as the store password - * - * @param storePath the path to the keyStore - * @param storePass the keyStore password - * @param keyAlias the alias of the key to use, may be {@code null} in which case the first key - * entry alias is used - * @return the customised KeyManager - * @throws IOException if there is a problem creating the keystore - * @throws GeneralSecurityException if there is a problem creating the keystore - */ - public static KeyManager createClientKeyManager(File storePath, String storePass, String keyAlias) - throws IOException, GeneralSecurityException { - return createClientKeyManager(DEFAULT_STORE_TYPE, storePath, storePass, keyAlias, storePass); - } - - /** - * Create a client key manager which returns a particular key. - * Does not handle server keys. - * Uses the default store type and assumes the key password is the same as the store password. - * The key alias is found by searching the keystore for the first private key entry - * - * @param storePath the path to the keyStore - * @param storePass the keyStore password - * @return the customised KeyManager - * @throws IOException if there is a problem creating the keystore - * @throws GeneralSecurityException if there is a problem creating the keystore - */ - public static KeyManager createClientKeyManager(File storePath, String storePass) - throws IOException, GeneralSecurityException { - return createClientKeyManager(DEFAULT_STORE_TYPE, storePath, storePass, null, storePass); - } - - private static KeyStore loadStore(String storeType, File storePath, String storePass) - throws KeyStoreException, IOException, GeneralSecurityException { - KeyStore ks = KeyStore.getInstance(storeType); - FileInputStream stream = null; - try { - stream = new FileInputStream(storePath); - ks.load(stream, storePass.toCharArray()); - } finally { - Util.closeQuietly(stream); - } - return ks; - } - - private static String findAlias(KeyStore ks) throws KeyStoreException { - Enumeration e = ks.aliases(); - while (e.hasMoreElements()) { - String entry = e.nextElement(); - if (ks.isKeyEntry(entry)) { - return entry; - } - } - throw new KeyStoreException("Cannot find a private key entry"); - } - - private static class ClientKeyStore { - - private final X509Certificate[] certChain; - private final PrivateKey key; - private final String keyAlias; - - ClientKeyStore(KeyStore ks, String keyAlias, String keyPass) throws GeneralSecurityException { - this.keyAlias = keyAlias; - this.key = (PrivateKey) ks.getKey(this.keyAlias, keyPass.toCharArray()); - Certificate[] certs = ks.getCertificateChain(this.keyAlias); - X509Certificate[] X509certs = new X509Certificate[certs.length]; - for (int i = 0; i < certs.length; i++) { - X509certs[i] = (X509Certificate) certs[i]; - } - this.certChain = X509certs; - } - - final X509Certificate[] getCertificateChain() { - return this.certChain; - } - - final PrivateKey getPrivateKey() { - return this.key; - } - - final String getAlias() { - return this.keyAlias; - } - } - - private static class X509KeyManager extends X509ExtendedKeyManager { - - private final ClientKeyStore keyStore; - - X509KeyManager(final ClientKeyStore keyStore) { - this.keyStore = keyStore; - } - - // Call sequence: 1 - @Override public String chooseClientAlias(String[] keyType, Principal[] issuers, - Socket socket) { - return keyStore.getAlias(); - } - - // Call sequence: 2 - @Override public X509Certificate[] getCertificateChain(String alias) { - return keyStore.getCertificateChain(); - } - - @Override public String[] getClientAliases(String keyType, Principal[] issuers) { - return new String[] { keyStore.getAlias() }; - } - - // Call sequence: 3 - @Override public PrivateKey getPrivateKey(String alias) { - return keyStore.getPrivateKey(); - } - - @Override public String[] getServerAliases(String keyType, Principal[] issuers) { - return null; - } - - @Override public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) { - return null; - } - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/ListenerList.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/ListenerList.java deleted file mode 100644 index 2ddfa637..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/ListenerList.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.util; - -import java.io.Serializable; -import java.util.EventListener; -import java.util.Iterator; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - */ - -public class ListenerList implements Serializable, Iterable { - private static final long serialVersionUID = -1934227607974228213L; - - private final CopyOnWriteArrayList __listeners; - - public ListenerList() { - __listeners = new CopyOnWriteArrayList(); - } - - public void addListener(EventListener listener) { - __listeners.add(listener); - } - - public void removeListener(EventListener listener) { - __listeners.remove(listener); - } - - public int getListenerCount() { - return __listeners.size(); - } - - /** - * Return an {@link Iterator} for the {@link EventListener} instances. - * - * @return an {@link Iterator} for the {@link EventListener} instances - * @since 2.0 - * TODO Check that this is a good defensive strategy - */ - @Override public Iterator iterator() { - return __listeners.iterator(); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/SSLContextUtils.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/SSLContextUtils.java deleted file mode 100644 index ddec2139..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/SSLContextUtils.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.util; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; - -/** - * General utilities for SSLContext. - * - * @since 3.0 - */ -public class SSLContextUtils { - - private SSLContextUtils() { - // Not instantiable - } - - /** - * Create and initialise an SSLContext. - * - * @param protocol the protocol used to instatiate the context - * @param keyManager the key manager, may be {@code null} - * @param trustManager the trust manager, may be {@code null} - * @return the initialised context. - * @throws IOException this is used to wrap any {@link GeneralSecurityException} that occurs - */ - public static SSLContext createSSLContext(String protocol, KeyManager keyManager, - TrustManager trustManager) throws IOException { - return createSSLContext(protocol, keyManager == null ? null : new KeyManager[] { keyManager }, - trustManager == null ? null : new TrustManager[] { trustManager }); - } - - /** - * Create and initialise an SSLContext. - * - * @param protocol the protocol used to instatiate the context - * @param keyManagers the array of key managers, may be {@code null} but array entries must not be - * {@code null} - * @param trustManagers the array of trust managers, may be {@code null} but array entries must - * not be {@code null} - * @return the initialised context. - * @throws IOException this is used to wrap any {@link GeneralSecurityException} that occurs - */ - public static SSLContext createSSLContext(String protocol, KeyManager[] keyManagers, - TrustManager[] trustManagers) throws IOException { - SSLContext ctx; - try { - ctx = SSLContext.getInstance(protocol); - ctx.init(keyManagers, trustManagers, /*SecureRandom*/ null); - } catch (GeneralSecurityException e) { - IOException ioe = new IOException("Could not initialize SSL context"); - ioe.initCause(e); - throw ioe; - } - return ctx; - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/SSLSocketUtils.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/SSLSocketUtils.java deleted file mode 100644 index 24f335ed..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/SSLSocketUtils.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.util; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import javax.net.ssl.SSLSocket; - -/** - * General utilities for SSLSocket. - * - * @since 3.4 - */ -public class SSLSocketUtils { - private SSLSocketUtils() { - // Not instantiable - } - - /** - * Enable the HTTPS endpoint identification algorithm on an SSLSocket. - * - * @param socket the SSL socket - * @return {@code true} on success (this is only supported on Java 1.7+) - */ - public static boolean enableEndpointNameVerification(SSLSocket socket) { - try { - Class cls = Class.forName("javax.net.ssl.SSLParameters"); - Method setEndpointIdentificationAlgorithm = - cls.getDeclaredMethod("setEndpointIdentificationAlgorithm", String.class); - Method getSSLParameters = SSLSocket.class.getDeclaredMethod("getSSLParameters"); - Method setSSLParameters = SSLSocket.class.getDeclaredMethod("setSSLParameters", cls); - if (setEndpointIdentificationAlgorithm != null - && getSSLParameters != null - && setSSLParameters != null) { - Object sslParams = getSSLParameters.invoke(socket); - if (sslParams != null) { - setEndpointIdentificationAlgorithm.invoke(sslParams, "HTTPS"); - setSSLParameters.invoke(socket, sslParams); - return true; - } - } - } catch (SecurityException e) { // Ignored - } catch (ClassNotFoundException e) { // Ignored - } catch (NoSuchMethodException e) { // Ignored - } catch (IllegalArgumentException e) { // Ignored - } catch (IllegalAccessException e) { // Ignored - } catch (InvocationTargetException e) { // Ignored - } - return false; - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/SubnetUtils.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/SubnetUtils.java deleted file mode 100644 index 9dd2e22e..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/SubnetUtils.java +++ /dev/null @@ -1,395 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.util; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * A class that performs some subnet calculations given a network address and a subnet mask. - * - * @see "http://www.faqs.org/rfcs/rfc1519.html" - * @since 2.0 - */ -public class SubnetUtils { - - private static final String IP_ADDRESS = "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})"; - private static final String SLASH_FORMAT = IP_ADDRESS + "/(\\d{1,3})"; - private static final Pattern addressPattern = Pattern.compile(IP_ADDRESS); - private static final Pattern cidrPattern = Pattern.compile(SLASH_FORMAT); - private static final int NBITS = 32; - - private int netmask = 0; - private int address = 0; - private int network = 0; - private int broadcast = 0; - - /** Whether the broadcast/network address are included in host count */ - private boolean inclusiveHostCount = false; - - /** - * Constructor that takes a CIDR-notation string, e.g. "192.168.0.1/16" - * - * @param cidrNotation A CIDR-notation string, e.g. "192.168.0.1/16" - * @throws IllegalArgumentException if the parameter is invalid, - * i.e. does not match n.n.n.n/m where n=1-3 decimal digits, m = 1-3 decimal digits in range 1-32 - */ - public SubnetUtils(String cidrNotation) { - calculate(cidrNotation); - } - - /** - * Constructor that takes a dotted decimal address and a dotted decimal mask. - * - * @param address An IP address, e.g. "192.168.0.1" - * @param mask A dotted decimal netmask e.g. "255.255.0.0" - * @throws IllegalArgumentException if the address or mask is invalid, - * i.e. does not match n.n.n.n where n=1-3 decimal digits and the mask is not all zeros - */ - public SubnetUtils(String address, String mask) { - calculate(toCidrNotation(address, mask)); - } - - /** - * Returns true if the return value of {@link SubnetInfo#getAddressCount()} - * includes the network and broadcast addresses. - * - * @return true if the hostcount includes the network and broadcast addresses - * @since 2.2 - */ - public boolean isInclusiveHostCount() { - return inclusiveHostCount; - } - - /** - * Set to true if you want the return value of {@link SubnetInfo#getAddressCount()} - * to include the network and broadcast addresses. - * - * @param inclusiveHostCount true if network and broadcast addresses are to be included - * @since 2.2 - */ - public void setInclusiveHostCount(boolean inclusiveHostCount) { - this.inclusiveHostCount = inclusiveHostCount; - } - - /** - * Convenience container for subnet summary information. - */ - public final class SubnetInfo { - /* Mask to convert unsigned int to a long (i.e. keep 32 bits) */ - private static final long UNSIGNED_INT_MASK = 0x0FFFFFFFFL; - - private SubnetInfo() { - } - - private int netmask() { - return netmask; - } - - private int network() { - return network; - } - - private int address() { - return address; - } - - private int broadcast() { - return broadcast; - } - - // long versions of the values (as unsigned int) which are more suitable for range checking - private long networkLong() { - return network & UNSIGNED_INT_MASK; - } - - private long broadcastLong() { - return broadcast & UNSIGNED_INT_MASK; - } - - private int low() { - return (isInclusiveHostCount() ? network() - : broadcastLong() - networkLong() > 1 ? network() + 1 : 0); - } - - private int high() { - return (isInclusiveHostCount() ? broadcast() - : broadcastLong() - networkLong() > 1 ? broadcast() - 1 : 0); - } - - /** - * Returns true if the parameter address is in the - * range of usable endpoint addresses for this subnet. This excludes the - * network and broadcast adresses. - * - * @param address A dot-delimited IPv4 address, e.g. "192.168.0.1" - * @return True if in range, false otherwise - */ - public boolean isInRange(String address) { - return isInRange(toInteger(address)); - } - - /** - * @param address the address to check - * @return true if it is in range - * @since 3.4 (made public) - */ - public boolean isInRange(int address) { - long addLong = address & UNSIGNED_INT_MASK; - long lowLong = low() & UNSIGNED_INT_MASK; - long highLong = high() & UNSIGNED_INT_MASK; - return addLong >= lowLong && addLong <= highLong; - } - - public String getBroadcastAddress() { - return format(toArray(broadcast())); - } - - public String getNetworkAddress() { - return format(toArray(network())); - } - - public String getNetmask() { - return format(toArray(netmask())); - } - - public String getAddress() { - return format(toArray(address())); - } - - /** - * Return the low address as a dotted IP address. - * Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false. - * - * @return the IP address in dotted format, may be "0.0.0.0" if there is no valid address - */ - public String getLowAddress() { - return format(toArray(low())); - } - - /** - * Return the high address as a dotted IP address. - * Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false. - * - * @return the IP address in dotted format, may be "0.0.0.0" if there is no valid address - */ - public String getHighAddress() { - return format(toArray(high())); - } - - /** - * Get the count of available addresses. - * Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false. - * - * @return the count of addresses, may be zero. - * @throws RuntimeException if the correct count is greater than {@code Integer.MAX_VALUE} - * @deprecated (3.4) use {@link #getAddressCountLong()} instead - */ - @Deprecated public int getAddressCount() { - long countLong = getAddressCountLong(); - if (countLong > Integer.MAX_VALUE) { - throw new RuntimeException("Count is larger than an integer: " + countLong); - } - // N.B. cannot be negative - return (int) countLong; - } - - /** - * Get the count of available addresses. - * Will be zero for CIDR/31 and CIDR/32 if the inclusive flag is false. - * - * @return the count of addresses, may be zero. - * @since 3.4 - */ - public long getAddressCountLong() { - long b = broadcastLong(); - long n = networkLong(); - long count = b - n + (isInclusiveHostCount() ? 1 : -1); - return count < 0 ? 0 : count; - } - - public int asInteger(String address) { - return toInteger(address); - } - - public String getCidrSignature() { - return toCidrNotation(format(toArray(address())), format(toArray(netmask()))); - } - - public String[] getAllAddresses() { - int ct = getAddressCount(); - String[] addresses = new String[ct]; - if (ct == 0) { - return addresses; - } - for (int add = low(), j = 0; add <= high(); ++add, ++j) { - addresses[j] = format(toArray(add)); - } - return addresses; - } - - /** - * {@inheritDoc} - * - * @since 2.2 - */ - @Override public String toString() { - final StringBuilder buf = new StringBuilder(); - buf.append("CIDR Signature:\t[") - .append(getCidrSignature()) - .append("]") - .append(" Netmask: [") - .append(getNetmask()) - .append("]\n") - .append("Network:\t[") - .append(getNetworkAddress()) - .append("]\n") - .append("Broadcast:\t[") - .append(getBroadcastAddress()) - .append("]\n") - .append("First Address:\t[") - .append(getLowAddress()) - .append("]\n") - .append("Last Address:\t[") - .append(getHighAddress()) - .append("]\n") - .append("# Addresses:\t[") - .append(getAddressCount()) - .append("]\n"); - return buf.toString(); - } - } - - /** - * Return a {@link SubnetInfo} instance that contains subnet-specific statistics - * - * @return new instance - */ - public final SubnetInfo getInfo() { - return new SubnetInfo(); - } - - /* - * Initialize the internal fields from the supplied CIDR mask - */ - private void calculate(String mask) { - Matcher matcher = cidrPattern.matcher(mask); - - if (matcher.matches()) { - address = matchAddress(matcher); - - /* Create a binary netmask from the number of bits specification /x */ - int cidrPart = rangeCheck(Integer.parseInt(matcher.group(5)), 0, NBITS); - for (int j = 0; j < cidrPart; ++j) { - netmask |= (1 << 31 - j); - } - - /* Calculate base network address */ - network = (address & netmask); - - /* Calculate broadcast address */ - broadcast = network | ~(netmask); - } else { - throw new IllegalArgumentException("Could not parse [" + mask + "]"); - } - } - - /* - * Convert a dotted decimal format address to a packed integer format - */ - private int toInteger(String address) { - Matcher matcher = addressPattern.matcher(address); - if (matcher.matches()) { - return matchAddress(matcher); - } else { - throw new IllegalArgumentException("Could not parse [" + address + "]"); - } - } - - /* - * Convenience method to extract the components of a dotted decimal address and - * pack into an integer using a regex match - */ - private int matchAddress(Matcher matcher) { - int addr = 0; - for (int i = 1; i <= 4; ++i) { - int n = (rangeCheck(Integer.parseInt(matcher.group(i)), 0, 255)); - addr |= ((n & 0xff) << 8 * (4 - i)); - } - return addr; - } - - /* - * Convert a packed integer address into a 4-element array - */ - private int[] toArray(int val) { - int ret[] = new int[4]; - for (int j = 3; j >= 0; --j) { - ret[j] |= ((val >>> 8 * (3 - j)) & (0xff)); - } - return ret; - } - - /* - * Convert a 4-element array into dotted decimal format - */ - private String format(int[] octets) { - StringBuilder str = new StringBuilder(); - for (int i = 0; i < octets.length; ++i) { - str.append(octets[i]); - if (i != octets.length - 1) { - str.append("."); - } - } - return str.toString(); - } - - /* - * Convenience function to check integer boundaries. - * Checks if a value x is in the range [begin,end]. - * Returns x if it is in range, throws an exception otherwise. - */ - private int rangeCheck(int value, int begin, int end) { - if (value >= begin && value <= end) { // (begin,end] - return value; - } - - throw new IllegalArgumentException( - "Value [" + value + "] not in range [" + begin + "," + end + "]"); - } - - /* - * Count the number of 1-bits in a 32-bit integer using a divide-and-conquer strategy - * see Hacker's Delight section 5.1 - */ - int pop(int x) { - x = x - ((x >>> 1) & 0x55555555); - x = (x & 0x33333333) + ((x >>> 2) & 0x33333333); - x = (x + (x >>> 4)) & 0x0F0F0F0F; - x = x + (x >>> 8); - x = x + (x >>> 16); - return x & 0x0000003F; - } - - /* Convert two dotted decimal addresses to a single xxx.xxx.xxx.xxx/yy format - * by counting the 1-bit population in the mask address. (It may be better to count - * NBITS-#trailing zeroes for this case) - */ - private String toCidrNotation(String addr, String mask) { - return addr + "/" + pop(toInteger(mask)); - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/TrustManagerUtils.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/TrustManagerUtils.java deleted file mode 100644 index a609f284..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/TrustManagerUtils.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 aria.apache.commons.net.util; - -import java.security.GeneralSecurityException; -import java.security.KeyStore; -import java.security.SecureRandom; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -import javax.net.ssl.KeyManager; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - -/** - * TrustManager utilities for generating TrustManagers. - * - * @since 3.0 - */ -public final class TrustManagerUtils { - private static final X509Certificate[] EMPTY_X509CERTIFICATE_ARRAY = new X509Certificate[] {}; - - private static class TrustManager implements X509TrustManager { - - private final boolean checkServerValidity; - - TrustManager(boolean checkServerValidity) { - this.checkServerValidity = checkServerValidity; - } - - /** - * Never generates a CertificateException. - */ - @Override public void checkClientTrusted(X509Certificate[] certificates, String authType) { - return; - } - - @Override public void checkServerTrusted(X509Certificate[] certificates, String authType) - throws CertificateException { - if (checkServerValidity) { - for (X509Certificate certificate : certificates) { - certificate.checkValidity(); - } - } - } - - /** - * @return an empty array of certificates - */ - @Override public X509Certificate[] getAcceptedIssuers() { - return EMPTY_X509CERTIFICATE_ARRAY; - } - } - - private static final X509TrustManager ACCEPT_ALL = new TrustManager(false); - - private static final X509TrustManager CHECK_SERVER_VALIDITY = new TrustManager(true); - - /** - * Generate a TrustManager that performs no checks. - * - * @return the TrustManager - */ - public static X509TrustManager getAcceptAllTrustManager() { - return ACCEPT_ALL; - } - - /** - * Generate a TrustManager that checks server certificates for validity, - * but otherwise performs no checks. - * - * @return the validating TrustManager - */ - public static X509TrustManager getValidateServerCertificateTrustManager() { - return CHECK_SERVER_VALIDITY; - } - - /** - * Return the default TrustManager provided by the JVM. - *

- * This should be the same as the default used by - * {@link javax.net.ssl.SSLContext#init(KeyManager[], javax.net.ssl.TrustManager[], SecureRandom)} - * SSLContext#init(KeyManager[], TrustManager[], SecureRandom)} - * when the TrustManager parameter is set to {@code null} - * - * @param keyStore the KeyStore to use, may be {@code null} - * @return the default TrustManager - * @throws GeneralSecurityException if an error occurs - */ - public static X509TrustManager getDefaultTrustManager(KeyStore keyStore) - throws GeneralSecurityException { - String defaultAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); - TrustManagerFactory instance = TrustManagerFactory.getInstance(defaultAlgorithm); - instance.init(keyStore); - return (X509TrustManager) instance.getTrustManagers()[0]; - } -} diff --git a/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/package-info.java b/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/package-info.java deleted file mode 100644 index 7b95d75d..00000000 --- a/AriaFtpPlug/src/main/java/aria/apache/commons/net/util/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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. - */ - -/** - * Utility classes - */ -package aria.apache.commons.net.util; \ No newline at end of file diff --git a/DEV_LOG.md b/DEV_LOG.md index 6d6cae72..e5633197 100644 --- a/DEV_LOG.md +++ b/DEV_LOG.md @@ -1,6 +1,8 @@ ## 开发日志 - + v_3.8.2 + + v_3.8.3 - fix bug https://github.com/AriaLyy/Aria/issues/573 + - android P适配 https://github.com/AriaLyy/Aria/issues/581 + - 添加ftp服务器标志 https://github.com/AriaLyy/Aria/issues/580 + v_3.8.1 (2019/12/22) - 修复一个表创建失败的问题 https://github.com/AriaLyy/Aria/issues/570 - 修复一个非分块模式下导致下载失败的问题 https://github.com/AriaLyy/Aria/issues/571 diff --git a/FtpComponent/src/main/java/com/arialyy/aria/ftp/AbsFtpInfoThread.java b/FtpComponent/src/main/java/com/arialyy/aria/ftp/AbsFtpInfoTask.java similarity index 94% rename from FtpComponent/src/main/java/com/arialyy/aria/ftp/AbsFtpInfoThread.java rename to FtpComponent/src/main/java/com/arialyy/aria/ftp/AbsFtpInfoTask.java index 3fa81ac6..ecac890a 100644 --- a/FtpComponent/src/main/java/com/arialyy/aria/ftp/AbsFtpInfoThread.java +++ b/FtpComponent/src/main/java/com/arialyy/aria/ftp/AbsFtpInfoTask.java @@ -28,8 +28,8 @@ import com.arialyy.aria.core.AriaConfig; import com.arialyy.aria.core.FtpUrlEntity; import com.arialyy.aria.core.common.AbsEntity; import com.arialyy.aria.core.common.FtpConnectionMode; -import com.arialyy.aria.core.inf.OnFileInfoCallback; -import com.arialyy.aria.core.upload.UploadEntity; +import com.arialyy.aria.core.loader.IInfoTask; +import com.arialyy.aria.core.loader.ILoaderVisitor; import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.exception.AriaIOException; import com.arialyy.aria.exception.TaskException; @@ -47,28 +47,24 @@ import javax.net.ssl.SSLContext; /** * Created by Aria.Lao on 2017/7/25. 获取ftp文件夹信息 */ -public abstract class AbsFtpInfoThread> - implements Runnable { +public abstract class AbsFtpInfoTask> + implements Runnable, IInfoTask { protected final String TAG = CommonUtil.getClassName(getClass()); protected ENTITY mEntity; protected TASK_WRAPPER mTaskWrapper; protected FtpTaskOption mTaskOption; private int mConnectTimeOut; - protected OnFileInfoCallback mCallback; protected long mSize = 0; protected String charSet = "UTF-8"; - private boolean isUpload = false; + protected boolean isUpload = false; + protected Callback callback; - public AbsFtpInfoThread(TASK_WRAPPER taskWrapper, OnFileInfoCallback callback) { + public AbsFtpInfoTask(TASK_WRAPPER taskWrapper) { mTaskWrapper = taskWrapper; mEntity = taskWrapper.getEntity(); mTaskOption = (FtpTaskOption) taskWrapper.getTaskOption(); mConnectTimeOut = AriaConfig.getInstance().getDConfig().getConnectTimeOut(); - mCallback = callback; - if (mEntity instanceof UploadEntity) { - isUpload = true; - } } /** @@ -78,6 +74,10 @@ public abstract class AbsFtpInfoThread { - private final String TAG = "FtpFileInfoThread"; +final class FtpDFileInfoTask extends AbsFtpInfoTask { - FtpDFileInfoThread(DTaskWrapper taskEntity, OnFileInfoCallback callback) { - super(taskEntity, callback); + FtpDFileInfoTask(DTaskWrapper taskEntity) { + super(taskEntity); } @Override protected void handleFile(String remotePath, FTPFile ftpFile) { super.handleFile(remotePath, ftpFile); - if (!FileUtil.checkSDMemorySpace(mEntity.getFilePath(), ftpFile.getSize())) { - mCallback.onFail(mEntity, new AriaIOException(TAG, + if (!FileUtil.checkMemorySpace(mEntity.getFilePath(), ftpFile.getSize())) { + callback.onFail(mEntity, new AriaIOException(TAG, String.format("获取ftp文件信息失败,内存空间不足, filePath: %s", mEntity.getFilePath())), false); } @@ -56,6 +54,6 @@ class FtpDFileInfoThread extends AbsFtpInfoThread mTaskWrapper.setNewTask(true); } mEntity.setFileSize(mSize); - mCallback.onComplete(mEntity.getUrl(), new CompleteInfo(code, mTaskWrapper)); + callback.onSucceed(mEntity.getUrl(), new CompleteInfo(code, mTaskWrapper)); } } diff --git a/FtpComponent/src/main/java/com/arialyy/aria/ftp/FtpDirInfoThread.java b/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDGInfoTask.java similarity index 72% rename from FtpComponent/src/main/java/com/arialyy/aria/ftp/FtpDirInfoThread.java rename to FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDGInfoTask.java index fa277f2c..ef97c7b7 100644 --- a/FtpComponent/src/main/java/com/arialyy/aria/ftp/FtpDirInfoThread.java +++ b/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDGInfoTask.java @@ -13,8 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.arialyy.aria.ftp; +package com.arialyy.aria.ftp.download; +import android.net.Uri; +import android.text.TextUtils; import aria.apache.commons.net.ftp.FTPClient; import aria.apache.commons.net.ftp.FTPFile; import com.arialyy.aria.core.FtpUrlEntity; @@ -23,8 +25,9 @@ import com.arialyy.aria.core.download.DGTaskWrapper; import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadGroupEntity; -import com.arialyy.aria.core.inf.OnFileInfoCallback; import com.arialyy.aria.core.wrapper.AbsTaskWrapper; +import com.arialyy.aria.ftp.AbsFtpInfoTask; +import com.arialyy.aria.ftp.FtpTaskOption; import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.RecordUtil; import java.nio.charset.Charset; @@ -33,10 +36,18 @@ import java.util.ArrayList; /** * Created by Aria.Lao on 2017/7/25. 获取ftp文件夹信息 */ -public class FtpDirInfoThread extends AbsFtpInfoThread { +final class FtpDGInfoTask extends AbsFtpInfoTask { - public FtpDirInfoThread(DGTaskWrapper taskEntity, OnFileInfoCallback callback) { - super(taskEntity, callback); + FtpDGInfoTask(DGTaskWrapper wrapper) { + super(wrapper); + } + + @Override public void run() { + if (mTaskWrapper.getEntity().getFileSize() > 1) { + callback.onSucceed(mEntity.getKey(), new CompleteInfo(200, mTaskWrapper)); + } else { + super.run(); + } } @Override protected String getRemotePath() { @@ -51,7 +62,29 @@ public class FtpDirInfoThread extends AbsFtpInfoThread= 200 && info.code < 300) { + startSub(); + } else { + ALog.e(TAG, "获取任务信息失败,code:" + info.code); + mListener.onFail(false, null); + } + } + + @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { + mListener.onFail(needRetry, e); + } + }); + } +} diff --git a/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDGLoaderUtil.java b/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDGLoaderUtil.java new file mode 100644 index 00000000..28f2e716 --- /dev/null +++ b/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDGLoaderUtil.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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.arialyy.aria.ftp.download; + +import com.arialyy.aria.core.download.DGTaskWrapper; +import com.arialyy.aria.core.group.AbsGroupLoader; +import com.arialyy.aria.core.group.AbsGroupLoaderUtil; +import com.arialyy.aria.core.listener.IEventListener; +import com.arialyy.aria.core.loader.LoaderStructure; +import com.arialyy.aria.core.wrapper.AbsTaskWrapper; +import com.arialyy.aria.ftp.FtpTaskOption; + +/** + * Created by Aria.Lao on 2017/7/27. + * ftp文件夹下载工具 + */ +public final class FtpDGLoaderUtil extends AbsGroupLoaderUtil { + + public FtpDGLoaderUtil(AbsTaskWrapper wrapper, IEventListener listener) { + super(wrapper, listener); + wrapper.generateTaskOption(FtpTaskOption.class); + } + + @Override protected AbsGroupLoader getLoader() { + return mLoader == null ? new FtpDGLoader(getTaskWrapper(), getListener()) : mLoader; + } + + @Override protected LoaderStructure buildLoaderStructure() { + LoaderStructure structure = new LoaderStructure(); + structure.addComponent(new FtpDGInfoTask((DGTaskWrapper) getTaskWrapper())); + structure.accept(getLoader()); + return structure; + } +} diff --git a/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDLoaderUtil.java b/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDLoaderUtil.java index 87e63a69..d05fca6e 100644 --- a/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDLoaderUtil.java +++ b/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDLoaderUtil.java @@ -15,46 +15,39 @@ */ package com.arialyy.aria.ftp.download; -import com.arialyy.aria.core.common.AbsEntity; -import com.arialyy.aria.core.common.CompleteInfo; import com.arialyy.aria.core.download.DTaskWrapper; -import com.arialyy.aria.core.inf.OnFileInfoCallback; import com.arialyy.aria.core.listener.IEventListener; -import com.arialyy.aria.core.loader.AbsLoader; +import com.arialyy.aria.core.loader.AbsNormalLoader; import com.arialyy.aria.core.loader.AbsNormalLoaderUtil; +import com.arialyy.aria.core.loader.LoaderStructure; import com.arialyy.aria.core.loader.NormalLoader; +import com.arialyy.aria.core.loader.NormalThreadStateManager; import com.arialyy.aria.core.wrapper.AbsTaskWrapper; -import com.arialyy.aria.exception.BaseException; +import com.arialyy.aria.ftp.FtpRecordHandler; import com.arialyy.aria.ftp.FtpTaskOption; /** * @Author lyy * @Date 2019-09-19 */ -public class FtpDLoaderUtil extends AbsNormalLoaderUtil { +public final class FtpDLoaderUtil extends AbsNormalLoaderUtil { public FtpDLoaderUtil(AbsTaskWrapper wrapper, IEventListener listener) { super(wrapper, listener); wrapper.generateTaskOption(FtpTaskOption.class); } - @Override protected AbsLoader createLoader() { - NormalLoader loader = new NormalLoader(getListener(), getTaskWrapper()); - loader.setAdapter(new FtpDLoaderAdapter(getTaskWrapper())); - return loader; + @Override public AbsNormalLoader getLoader() { + return mLoader == null ? new NormalLoader(getTaskWrapper(), getListener()) : mLoader; } - @Override protected Runnable createInfoThread() { - return new FtpDFileInfoThread((DTaskWrapper) getTaskWrapper(), new OnFileInfoCallback() { - @Override public void onComplete(String url, CompleteInfo info) { - ((NormalLoader) getLoader()).updateTempFile(); - getLoader().start(); - } - - @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { - fail(e, needRetry); - getLoader().closeTimer(); - } - }); + public LoaderStructure BuildLoaderStructure() { + LoaderStructure structure = new LoaderStructure(); + structure.addComponent(new FtpRecordHandler(getTaskWrapper())) + .addComponent(new NormalThreadStateManager(getListener())) + .addComponent(new FtpDFileInfoTask((DTaskWrapper) getTaskWrapper())) + .addComponent(new FtpDTTBuilder(getTaskWrapper())); + structure.accept(getLoader()); + return structure; } } diff --git a/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDLoaderAdapter.java b/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDTTBuilder.java similarity index 64% rename from FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDLoaderAdapter.java rename to FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDTTBuilder.java index 6e81ef70..f69a33e8 100644 --- a/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDLoaderAdapter.java +++ b/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDTTBuilder.java @@ -16,15 +16,11 @@ package com.arialyy.aria.ftp.download; import com.arialyy.aria.core.TaskRecord; -import com.arialyy.aria.core.common.RecordHandler; import com.arialyy.aria.core.common.SubThreadConfig; +import com.arialyy.aria.core.loader.AbsNormalTTBuilder; import com.arialyy.aria.core.loader.IRecordHandler; -import com.arialyy.aria.core.task.AbsNormalLoaderAdapter; -import com.arialyy.aria.core.task.IThreadTask; -import com.arialyy.aria.core.task.ThreadTask; +import com.arialyy.aria.core.task.IThreadTaskAdapter; import com.arialyy.aria.core.wrapper.AbsTaskWrapper; -import com.arialyy.aria.core.wrapper.ITaskWrapper; -import com.arialyy.aria.ftp.FtpRecordHandler; import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.FileUtil; import java.io.File; @@ -33,12 +29,16 @@ import java.io.File; * @Author lyy * @Date 2019-09-19 */ -public class FtpDLoaderAdapter extends AbsNormalLoaderAdapter { +final class FtpDTTBuilder extends AbsNormalTTBuilder { - public FtpDLoaderAdapter(ITaskWrapper wrapper) { + FtpDTTBuilder(AbsTaskWrapper wrapper) { super(wrapper); } + @Override public IThreadTaskAdapter getAdapter(SubThreadConfig config) { + return new FtpDThreadTaskAdapter(config); + } + @Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) { if (!record.isBlock) { if (getTempFile().exists()) { @@ -57,18 +57,4 @@ public class FtpDLoaderAdapter extends AbsNormalLoaderAdapter { } return true; } - - @Override public IThreadTask createThreadTask(SubThreadConfig config) { - ThreadTask threadTask = new ThreadTask(config); - FtpDThreadTaskAdapter adapter = new FtpDThreadTaskAdapter(config); - threadTask.setAdapter(adapter); - return threadTask; - } - - @Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) { - FtpRecordHandler adapter = new FtpRecordHandler(wrapper); - RecordHandler handler = new RecordHandler(wrapper); - handler.setAdapter(adapter); - return handler; - } } diff --git a/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDirDLoaderUtil.java b/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDirDLoaderUtil.java deleted file mode 100644 index e58a665b..00000000 --- a/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpDirDLoaderUtil.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) - * - * 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.arialyy.aria.ftp.download; - -import android.net.Uri; -import android.text.TextUtils; -import com.arialyy.aria.core.FtpUrlEntity; -import com.arialyy.aria.core.common.AbsEntity; -import com.arialyy.aria.core.common.CompleteInfo; -import com.arialyy.aria.core.download.DTaskWrapper; -import com.arialyy.aria.core.group.AbsGroupLoaderUtil; -import com.arialyy.aria.core.group.AbsSubDLoadUtil; -import com.arialyy.aria.core.inf.IEntity; -import com.arialyy.aria.core.inf.OnFileInfoCallback; -import com.arialyy.aria.core.listener.IEventListener; -import com.arialyy.aria.core.wrapper.AbsTaskWrapper; -import com.arialyy.aria.exception.BaseException; -import com.arialyy.aria.ftp.FtpDirInfoThread; -import com.arialyy.aria.ftp.FtpTaskOption; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.ReentrantLock; - -/** - * Created by Aria.Lao on 2017/7/27. - * ftp文件夹下载工具 - */ -public class FtpDirDLoaderUtil extends AbsGroupLoaderUtil { - private ReentrantLock LOCK = new ReentrantLock(); - private Condition condition = LOCK.newCondition(); - - public FtpDirDLoaderUtil(AbsTaskWrapper wrapper, IEventListener listener) { - super(wrapper, listener); - wrapper.generateTaskOption(FtpTaskOption.class); - } - - @Override - protected AbsSubDLoadUtil createSubLoader(DTaskWrapper wrapper, boolean needGetFileInfo) { - return new FtpSubDLoaderUtil(getScheduler(), wrapper, needGetFileInfo); - } - - @Override protected boolean onStart() { - super.onStart(); - - if (getWrapper().getEntity().getFileSize() > 1) { - startDownload(true); - } else { - FtpDirInfoThread infoThread = new FtpDirInfoThread(getWrapper(), new OnFileInfoCallback() { - @Override public void onComplete(String url, CompleteInfo info) { - if (info.code >= 200 && info.code < 300) { - startDownload(false); - } - } - - @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { - mListener.onFail(needRetry, e); - } - }); - new Thread(infoThread).start(); - try { - LOCK.lock(); - condition.await(); - } catch (InterruptedException e) { - e.printStackTrace(); - } finally { - LOCK.unlock(); - } - } - return true; - } - - /** - * @param needCloneInfo 第一次下载,信息已经在{@link FtpDirInfoThread}中clone了 - */ - private void startDownload(boolean needCloneInfo) { - // ftp需要获取完成只任务信息才更新只任务数量 - getState().setSubSize(getWrapper().getSubTaskWrapper().size()); - try { - LOCK.lock(); - condition.signalAll(); - } finally { - LOCK.unlock(); - } - for (DTaskWrapper wrapper : getWrapper().getSubTaskWrapper()) { - if (needCloneInfo) { - cloneInfo(wrapper); - } - if (wrapper.getState() != IEntity.STATE_COMPLETE) { - startSubLoader(createSubLoader(wrapper, true)); - } - } - } - - private void cloneInfo(DTaskWrapper subWrapper) { - FtpTaskOption option = (FtpTaskOption) getWrapper().getTaskOption(); - FtpUrlEntity urlEntity = option.getUrlEntity().clone(); - Uri uri = Uri.parse(subWrapper.getEntity().getUrl()); - String remotePath = uri.getPath(); - urlEntity.remotePath = TextUtils.isEmpty(remotePath) ? "/" : remotePath; - - FtpTaskOption subOption = new FtpTaskOption(); - subOption.setUrlEntity(urlEntity); - subOption.setCharSet(option.getCharSet()); - subOption.setProxy(option.getProxy()); - subOption.setClientConfig(option.getClientConfig()); - subOption.setNewFileName(option.getNewFileName()); - subOption.setProxy(option.getProxy()); - subOption.setUploadInterceptor(option.getUploadInterceptor()); - - subWrapper.setTaskOption(subOption); - } -} diff --git a/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpSubDLoaderUtil.java b/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpSubDLoaderUtil.java index ec2cb3b5..1617cb18 100644 --- a/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpSubDLoaderUtil.java +++ b/FtpComponent/src/main/java/com/arialyy/aria/ftp/download/FtpSubDLoaderUtil.java @@ -18,30 +18,37 @@ package com.arialyy.aria.ftp.download; import android.os.Handler; import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.group.AbsSubDLoadUtil; -import com.arialyy.aria.core.group.ChildDLoadListener; -import com.arialyy.aria.core.loader.NormalLoader; +import com.arialyy.aria.core.loader.LoaderStructure; +import com.arialyy.aria.core.loader.SubLoader; +import com.arialyy.aria.ftp.FtpRecordHandler; /** * @Author lyy * @Date 2019-09-28 */ -class FtpSubDLoaderUtil extends AbsSubDLoadUtil { +final class FtpSubDLoaderUtil extends AbsSubDLoadUtil { /** * @param schedulers 调度器 * @param needGetInfo {@code true} 需要获取文件信息。{@code false} 不需要获取文件信息 */ - FtpSubDLoaderUtil(Handler schedulers, DTaskWrapper taskWrapper, boolean needGetInfo) { - super(schedulers, taskWrapper, needGetInfo); + FtpSubDLoaderUtil(DTaskWrapper taskWrapper, Handler schedulers, boolean needGetInfo) { + super(taskWrapper, schedulers, needGetInfo); } - @Override protected NormalLoader createLoader(ChildDLoadListener listener, DTaskWrapper wrapper) { - NormalLoader loader = new NormalLoader(listener, wrapper); - FtpDLoaderAdapter adapter = new FtpDLoaderAdapter(wrapper); - loader.setAdapter(adapter); - return loader; + @Override protected SubLoader getLoader() { + if (mDLoader == null) { + mDLoader = new SubLoader(getWrapper(), getSchedulers()); + mDLoader.setNeedGetInfo(isNeedGetInfo()); + } + return mDLoader; } - @Override public void start() { - getDownloader().start(); + @Override protected LoaderStructure buildLoaderStructure() { + LoaderStructure structure = new LoaderStructure(); + structure.addComponent(new FtpRecordHandler(getWrapper())) + .addComponent(new FtpDTTBuilder(getWrapper())) + .addComponent(new FtpDFileInfoTask(getWrapper())); + structure.accept(getLoader()); + return structure; } } diff --git a/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpUFileInfoThread.java b/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpUFileInfoTask.java similarity index 94% rename from FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpUFileInfoThread.java rename to FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpUFileInfoTask.java index 9ffc376e..3ca77eb1 100644 --- a/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpUFileInfoThread.java +++ b/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpUFileInfoTask.java @@ -21,12 +21,11 @@ import aria.apache.commons.net.ftp.FTPFile; import com.arialyy.aria.core.TaskRecord; import com.arialyy.aria.core.ThreadRecord; import com.arialyy.aria.core.common.CompleteInfo; -import com.arialyy.aria.core.inf.OnFileInfoCallback; import com.arialyy.aria.core.processor.FtpInterceptHandler; import com.arialyy.aria.core.processor.IFtpUploadInterceptor; import com.arialyy.aria.core.upload.UTaskWrapper; import com.arialyy.aria.core.upload.UploadEntity; -import com.arialyy.aria.ftp.AbsFtpInfoThread; +import com.arialyy.aria.ftp.AbsFtpInfoTask; import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.DbDataHelper; @@ -38,13 +37,14 @@ import java.util.List; * Created by Aria.Lao on 2017/9/26. * 单任务上传远程服务器文件信息 */ -class FtpUFileInfoThread extends AbsFtpInfoThread { +final class FtpUFileInfoTask extends AbsFtpInfoTask { static final int CODE_COMPLETE = 0xab1; private boolean isComplete = false; private String remotePath; - FtpUFileInfoThread(UTaskWrapper taskEntity, OnFileInfoCallback callback) { - super(taskEntity, callback); + FtpUFileInfoTask(UTaskWrapper taskEntity) { + super(taskEntity); + isUpload = true; } @Override protected String getRemotePath() { @@ -161,7 +161,7 @@ class FtpUFileInfoThread extends AbsFtpInfoThread { @Override protected void onPreComplete(int code) { super.onPreComplete(code); - mCallback.onComplete(mEntity.getKey(), + callback.onSucceed(mEntity.getKey(), new CompleteInfo(isComplete ? CODE_COMPLETE : code, mTaskWrapper)); } } diff --git a/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpULoader.java b/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpULoader.java new file mode 100644 index 00000000..21076650 --- /dev/null +++ b/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpULoader.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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.arialyy.aria.ftp.upload; + +import com.arialyy.aria.core.common.AbsEntity; +import com.arialyy.aria.core.common.CompleteInfo; +import com.arialyy.aria.core.listener.IEventListener; +import com.arialyy.aria.core.loader.IInfoTask; +import com.arialyy.aria.core.loader.NormalLoader; +import com.arialyy.aria.core.wrapper.AbsTaskWrapper; +import com.arialyy.aria.exception.BaseException; + +final class FtpULoader extends NormalLoader { + FtpULoader(AbsTaskWrapper wrapper, IEventListener listener) { + super(wrapper, listener); + } + + @Override public void addComponent(IInfoTask infoTask) { + mInfoTask = infoTask; + infoTask.setCallback(new IInfoTask.Callback() { + @Override public void onSucceed(String key, CompleteInfo info) { + if (info.code == FtpUFileInfoTask.CODE_COMPLETE) { + getListener().onComplete(); + } else { + startThreadTask(); + } + } + + @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { + getListener().onFail(needRetry, e); + } + }); + } +} diff --git a/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpULoaderUtil.java b/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpULoaderUtil.java index c2dacef2..b8fe8589 100644 --- a/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpULoaderUtil.java +++ b/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpULoaderUtil.java @@ -15,50 +15,38 @@ */ package com.arialyy.aria.ftp.upload; -import com.arialyy.aria.core.common.AbsEntity; -import com.arialyy.aria.core.common.CompleteInfo; -import com.arialyy.aria.core.download.DTaskWrapper; -import com.arialyy.aria.core.inf.OnFileInfoCallback; import com.arialyy.aria.core.listener.IEventListener; -import com.arialyy.aria.core.listener.IUploadListener; -import com.arialyy.aria.core.loader.AbsLoader; +import com.arialyy.aria.core.loader.AbsNormalLoader; import com.arialyy.aria.core.loader.AbsNormalLoaderUtil; -import com.arialyy.aria.core.loader.NormalLoader; +import com.arialyy.aria.core.loader.LoaderStructure; +import com.arialyy.aria.core.loader.NormalThreadStateManager; import com.arialyy.aria.core.upload.UTaskWrapper; import com.arialyy.aria.core.wrapper.AbsTaskWrapper; -import com.arialyy.aria.exception.BaseException; +import com.arialyy.aria.ftp.FtpRecordHandler; import com.arialyy.aria.ftp.FtpTaskOption; /** * @Author lyy * @Date 2019-09-19 */ -public class FtpULoaderUtil extends AbsNormalLoaderUtil { +public final class FtpULoaderUtil extends AbsNormalLoaderUtil { public FtpULoaderUtil(AbsTaskWrapper wrapper, IEventListener listener) { super(wrapper, listener); wrapper.generateTaskOption(FtpTaskOption.class); } - @Override protected AbsLoader createLoader() { - NormalLoader loader = new NormalLoader(getListener(), getTaskWrapper()); - loader.setAdapter(new FtpULoaferAdapter(getTaskWrapper())); - return loader; + @Override public AbsNormalLoader getLoader() { + return mLoader == null ? new FtpULoader(getTaskWrapper(), getListener()) : mLoader; } - @Override protected Runnable createInfoThread() { - return new FtpUFileInfoThread((UTaskWrapper) getTaskWrapper(), new OnFileInfoCallback() { - @Override public void onComplete(String url, CompleteInfo info) { - if (info.code == FtpUFileInfoThread.CODE_COMPLETE) { - getListener().onComplete(); - } else { - getLoader().start(); - } - } - - @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { - fail(e, needRetry); - } - }); + @Override public LoaderStructure BuildLoaderStructure() { + LoaderStructure structure = new LoaderStructure(); + structure.addComponent(new FtpRecordHandler(getTaskWrapper())) + .addComponent(new NormalThreadStateManager(getListener())) + .addComponent(new FtpUFileInfoTask((UTaskWrapper) getTaskWrapper())) + .addComponent(new FtpUTTBuilder(getTaskWrapper())); + structure.accept(getLoader()); + return structure; } } diff --git a/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpULoaferAdapter.java b/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpUTTBuilder.java similarity index 50% rename from FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpULoaferAdapter.java rename to FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpUTTBuilder.java index 3ec3312f..d111bcba 100644 --- a/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpULoaferAdapter.java +++ b/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpUTTBuilder.java @@ -16,41 +16,26 @@ package com.arialyy.aria.ftp.upload; import com.arialyy.aria.core.TaskRecord; -import com.arialyy.aria.core.task.AbsNormalLoaderAdapter; -import com.arialyy.aria.core.common.RecordHandler; import com.arialyy.aria.core.common.SubThreadConfig; -import com.arialyy.aria.core.task.ThreadTask; +import com.arialyy.aria.core.loader.AbsNormalTTBuilder; +import com.arialyy.aria.core.task.IThreadTaskAdapter; import com.arialyy.aria.core.wrapper.AbsTaskWrapper; -import com.arialyy.aria.core.loader.IRecordHandler; -import com.arialyy.aria.core.task.IThreadTask; -import com.arialyy.aria.core.wrapper.ITaskWrapper; -import com.arialyy.aria.ftp.FtpRecordHandler; /** * @Author lyy * @Date 2019-09-19 */ -class FtpULoaferAdapter extends AbsNormalLoaderAdapter { +final class FtpUTTBuilder extends AbsNormalTTBuilder { - FtpULoaferAdapter(ITaskWrapper wrapper) { + FtpUTTBuilder(AbsTaskWrapper wrapper) { super(wrapper); } - @Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) { - return true; - } - - @Override public IThreadTask createThreadTask(SubThreadConfig config) { - ThreadTask threadTask = new ThreadTask(config); - FtpUThreadTaskAdapter adapter = new FtpUThreadTaskAdapter(config); - threadTask.setAdapter(adapter); - return threadTask; + @Override public IThreadTaskAdapter getAdapter(SubThreadConfig config) { + return new FtpUThreadTaskAdapter(config); } - @Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) { - FtpRecordHandler adapter = new FtpRecordHandler(wrapper); - RecordHandler handler = new RecordHandler(wrapper); - handler.setAdapter(adapter); - return handler; + @Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) { + return true; } } diff --git a/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpUThreadTaskAdapter.java b/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpUThreadTaskAdapter.java index c8da304c..6b8d9aa7 100644 --- a/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpUThreadTaskAdapter.java +++ b/FtpComponent/src/main/java/com/arialyy/aria/ftp/upload/FtpUThreadTaskAdapter.java @@ -34,7 +34,7 @@ import java.util.concurrent.TimeUnit; /** * Created by Aria.Lao on 2017/7/28. D_FTP 单线程上传任务,需要FTP 服务器给用户打开append和write的权限 */ -class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter { +final class FtpUThreadTaskAdapter extends BaseFtpThreadTaskAdapter { private String dir, remotePath; private boolean storeFail = false; private ScheduledThreadPoolExecutor timer; diff --git a/HttpComponent/src/main/java/com/arialyy/aria/http/ConnectionHelp.java b/HttpComponent/src/main/java/com/arialyy/aria/http/ConnectionHelp.java index 3c92381f..f4e42747 100644 --- a/HttpComponent/src/main/java/com/arialyy/aria/http/ConnectionHelp.java +++ b/HttpComponent/src/main/java/com/arialyy/aria/http/ConnectionHelp.java @@ -43,7 +43,7 @@ import javax.net.ssl.SSLSocketFactory; /** * Created by lyy on 2017/1/18. 链接帮助类 */ -public class ConnectionHelp { +public final class ConnectionHelp { private static final String TAG = "ConnectionHelp"; /** diff --git a/HttpComponent/src/main/java/com/arialyy/aria/http/HttpFileInfoTask.java b/HttpComponent/src/main/java/com/arialyy/aria/http/HttpFileInfoTask.java index 7d877bc7..24d9236f 100644 --- a/HttpComponent/src/main/java/com/arialyy/aria/http/HttpFileInfoTask.java +++ b/HttpComponent/src/main/java/com/arialyy/aria/http/HttpFileInfoTask.java @@ -55,7 +55,7 @@ import java.util.UUID; /** * 下载文件信息获取 */ -public class HttpFileInfoTask implements IInfoTask, Runnable { +public final class HttpFileInfoTask implements IInfoTask, Runnable { private static final String TAG = "HttpFileInfoThread"; private DownloadEntity mEntity; private DTaskWrapper mTaskWrapper; @@ -129,7 +129,7 @@ public class HttpFileInfoTask implements IInfoTask, Runnable { } long len = lenAdapter.handleFileLen(conn.getHeaderFields()); - if (!FileUtil.checkSDMemorySpace(mEntity.getFilePath(), len)) { + if (!FileUtil.checkMemorySpace(mEntity.getFilePath(), len)) { failDownload(new TaskException(TAG, String.format("下载失败,内存空间不足;filePath: %s, url: %s", mEntity.getDownloadPath(), mEntity.getUrl())), false); diff --git a/HttpComponent/src/main/java/com/arialyy/aria/http/HttpRecordHandler.java b/HttpComponent/src/main/java/com/arialyy/aria/http/HttpRecordHandler.java index ecdbbe0f..997770c8 100644 --- a/HttpComponent/src/main/java/com/arialyy/aria/http/HttpRecordHandler.java +++ b/HttpComponent/src/main/java/com/arialyy/aria/http/HttpRecordHandler.java @@ -31,7 +31,7 @@ import java.util.ArrayList; * @Author lyy * @Date 2019-09-23 */ -public class HttpRecordHandler extends RecordHandler { +public final class HttpRecordHandler extends RecordHandler { public HttpRecordHandler(AbsTaskWrapper wrapper) { super(wrapper); } @@ -45,7 +45,7 @@ public class HttpRecordHandler extends RecordHandler { @Override public void handlerTaskRecord(TaskRecord record) { RecordHelper helper = new RecordHelper(getWrapper(), record); - if (getWrapper().isSupportBP()) { + if (getWrapper().isSupportBP() && record.threadNum > 1) { if (record.isBlock) { helper.handleBlockRecord(); } else { @@ -70,10 +70,10 @@ public class HttpRecordHandler extends RecordHandler { tr.threadType = getEntity().getTaskType(); //最后一个线程的结束位置即为文件的总长度 if (threadId == (record.threadNum - 1)) { - endL = getEntity().getFileSize(); + endL = getFileSize(); } tr.endLocation = endL; - tr.blockLen = RecordUtil.getBlockLen(getEntity().getFileSize(), threadId, record.threadNum); + tr.blockLen = RecordUtil.getBlockLen(getFileSize(), threadId, record.threadNum); return tr; } @@ -110,7 +110,7 @@ public class HttpRecordHandler extends RecordHandler { return 1; } int threadNum = Configuration.getInstance().downloadCfg.getThreadNum(); - return getEntity().getFileSize() <= IRecordHandler.SUB_LEN + return getFileSize() <= IRecordHandler.SUB_LEN || getEntity().isGroupChild() || threadNum == 1 ? 1 diff --git a/HttpComponent/src/main/java/com/arialyy/aria/http/HttpTaskOption.java b/HttpComponent/src/main/java/com/arialyy/aria/http/HttpTaskOption.java index fb898c70..116365f5 100644 --- a/HttpComponent/src/main/java/com/arialyy/aria/http/HttpTaskOption.java +++ b/HttpComponent/src/main/java/com/arialyy/aria/http/HttpTaskOption.java @@ -29,7 +29,7 @@ import java.util.Map; /** * Http任务设置的信息,如:cookie、请求参数 */ -public class HttpTaskOption implements ITaskOption { +public final class HttpTaskOption implements ITaskOption { private CookieManager cookieManager; diff --git a/HttpComponent/src/main/java/com/arialyy/aria/http/download/DGroupLoaderUtil.java b/HttpComponent/src/main/java/com/arialyy/aria/http/download/DGroupLoaderUtil.java deleted file mode 100644 index f2e457e4..00000000 --- a/HttpComponent/src/main/java/com/arialyy/aria/http/download/DGroupLoaderUtil.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) - * - * 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.arialyy.aria.http.download; - -import com.arialyy.aria.core.common.AbsEntity; -import com.arialyy.aria.core.common.CompleteInfo; -import com.arialyy.aria.core.download.DTaskWrapper; -import com.arialyy.aria.core.download.DownloadEntity; -import com.arialyy.aria.core.inf.IEntity; -import com.arialyy.aria.core.inf.OnFileInfoCallback; -import com.arialyy.aria.core.listener.IEventListener; -import com.arialyy.aria.core.wrapper.AbsTaskWrapper; -import com.arialyy.aria.exception.AriaIOException; -import com.arialyy.aria.exception.BaseException; -import com.arialyy.aria.core.group.AbsGroupLoaderUtil; -import com.arialyy.aria.core.group.AbsSubDLoadUtil; -import com.arialyy.aria.http.HttpFileInfoTask; -import com.arialyy.aria.http.HttpTaskOption; -import com.arialyy.aria.util.ALog; -import com.arialyy.aria.util.CommonUtil; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * Created by AriaL on 2017/6/30. - * 任务组下载工具 - */ -public class DGroupLoaderUtil extends AbsGroupLoaderUtil { - private final Object LOCK = new Object(); - private ExecutorService mPool = null; - private boolean getLenComplete = false; - private List mTempWrapper = new ArrayList<>(); - - public DGroupLoaderUtil(AbsTaskWrapper taskWrapper, IEventListener listener) { - super(taskWrapper, listener); - taskWrapper.generateTaskOption(HttpTaskOption.class); - } - - @Override - protected AbsSubDLoadUtil createSubLoader(DTaskWrapper wrapper, boolean needGetFileInfo) { - return new HttpSubDLoaderUtil(getScheduler(), wrapper, needGetFileInfo); - } - - @Override public void onPreCancel() { - super.onPreCancel(); - } - - @Override protected boolean onPreStop() { - // 如果是isUnknownSize()标志,并且获取大小没有完成,则直接回调onStop - if (mPool != null && !getLenComplete) { - ALog.d(TAG, "获取长度未完成的情况下,停止组合任务"); - mPool.shutdown(); - mListener.onStop(0); - return true; - } - return false; - } - - @Override protected boolean onStart() { - super.onStart(); - getState().setSubSize(getWrapper().getSubTaskWrapper().size()); - if (getState().getCompleteNum() == getState().getSubSize()) { - mListener.onComplete(); - return false; - } else { - // 处理组合任务大小未知的情况 - if (getWrapper().isUnknownSize() && getWrapper().getEntity().getFileSize() < 1) { - mPool = Executors.newCachedThreadPool(); - getGroupSize(); - try { - synchronized (LOCK) { - LOCK.wait(); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - return getLenComplete; - } else { - for (DTaskWrapper wrapper : getWrapper().getSubTaskWrapper()) { - cloneHeader(wrapper); - if (wrapper.getState() != IEntity.STATE_COMPLETE) { - startSubLoader(createSubLoader(wrapper, true)); - } - } - } - } - return true; - } - - /** - * 获取组合任务大小,使用该方式获取到的组合任务大小,子任务不需要再重新获取文件大小 - */ - private void getGroupSize() { - new Thread(new Runnable() { - int count; - int failCount; - - @Override public void run() { - for (DTaskWrapper dTaskWrapper : getWrapper().getSubTaskWrapper()) { - cloneHeader(dTaskWrapper); - mPool.submit(new HttpFileInfoTask(dTaskWrapper, new OnFileInfoCallback() { - @Override public void onComplete(String url, CompleteInfo info) { - if (!getWrapper().isUnknownSize()) { - startSubLoader(createSubLoader((DTaskWrapper) info.wrapper, false)); - } else { - mTempWrapper.add((DTaskWrapper) info.wrapper); - } - count++; - checkGetSizeComplete(count, failCount); - ALog.d(TAG, "获取子任务信息完成"); - } - - @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { - ALog.e(TAG, String.format("获取文件信息失败,url:%s", ((DownloadEntity) entity).getUrl())); - count++; - failCount++; - mListener.onSubFail((DownloadEntity) entity, new AriaIOException(TAG, - String.format("子任务获取文件长度失败,url:%s", ((DownloadEntity) entity).getUrl()))); - checkGetSizeComplete(count, failCount); - getState().countFailNum(entity.getKey()); - } - })); - } - } - }).start(); - } - - /** - * 检查组合任务大小是否获取完成,获取完成后取消阻塞,并设置组合任务大小 - */ - private void checkGetSizeComplete(int count, int failCount) { - if (failCount == getWrapper().getSubTaskWrapper().size()) { - getState().setRunning(false); - mListener.onFail(false, new AriaIOException(TAG, "获取子任务长度失败")); - notifyLock(); - return; - } - if (count == getWrapper().getSubTaskWrapper().size()) { - long size = 0; - for (DTaskWrapper wrapper : getWrapper().getSubTaskWrapper()) { - size += wrapper.getEntity().getFileSize(); - } - getWrapper().getEntity().setConvertFileSize(CommonUtil.formatFileSize(size)); - getWrapper().getEntity().setFileSize(size); - getWrapper().getEntity().update(); - getLenComplete = true; - ALog.d(TAG, String.format("获取组合任务长度完成,组合任务总长度:%s,失败的只任务数:%s", size, failCount)); - // 未知大小的组合任务,延迟下载 - if (getWrapper().isUnknownSize()) { - for (DTaskWrapper wrapper : mTempWrapper) { - startSubLoader(createSubLoader(wrapper, false)); - } - } - notifyLock(); - } - } - - private void notifyLock() { - synchronized (LOCK) { - LOCK.notifyAll(); - } - } - - /** - * 子任务使用父包裹器的属性 - */ - private void cloneHeader(DTaskWrapper taskWrapper) { - HttpTaskOption groupOption = (HttpTaskOption) getWrapper().getTaskOption(); - HttpTaskOption subOption = new HttpTaskOption(); - - // 设置属性 - subOption.setFileLenAdapter(groupOption.getFileLenAdapter()); - subOption.setRequestEnum(groupOption.getRequestEnum()); - subOption.setHeaders(groupOption.getHeaders()); - subOption.setProxy(groupOption.getProxy()); - subOption.setParams(groupOption.getParams()); - taskWrapper.setTaskOption(subOption); - } -} \ No newline at end of file diff --git a/HttpComponent/src/main/java/com/arialyy/aria/http/HttpGroupInfoTask.java b/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDGInfoTask.java similarity index 94% rename from HttpComponent/src/main/java/com/arialyy/aria/http/HttpGroupInfoTask.java rename to HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDGInfoTask.java index e7ecacf5..2e4d9123 100644 --- a/HttpComponent/src/main/java/com/arialyy/aria/http/HttpGroupInfoTask.java +++ b/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDGInfoTask.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.arialyy.aria.http; +package com.arialyy.aria.http.download; import com.arialyy.aria.core.common.AbsEntity; import com.arialyy.aria.core.common.CompleteInfo; @@ -25,6 +25,8 @@ import com.arialyy.aria.core.loader.IInfoTask; import com.arialyy.aria.core.loader.ILoaderVisitor; import com.arialyy.aria.exception.AriaIOException; import com.arialyy.aria.exception.BaseException; +import com.arialyy.aria.http.HttpFileInfoTask; +import com.arialyy.aria.http.HttpTaskOption; import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.CommonUtil; import java.util.concurrent.ExecutorService; @@ -33,7 +35,7 @@ import java.util.concurrent.Executors; /** * 组合任务文件信息,用于获取长度未知时,组合任务的长度 */ -public class HttpGroupInfoTask implements IInfoTask { +public final class HttpDGInfoTask implements IInfoTask { private String TAG = CommonUtil.getClassName(this); private Callback callback; private DGTaskWrapper wrapper; @@ -64,7 +66,7 @@ public class HttpGroupInfoTask implements IInfoTask { } }; - public HttpGroupInfoTask(DGTaskWrapper wrapper, DownloadGroupListener listener) { + public HttpDGInfoTask(DGTaskWrapper wrapper, DownloadGroupListener listener) { this.wrapper = wrapper; this.listener = listener; } @@ -96,7 +98,7 @@ public class HttpGroupInfoTask implements IInfoTask { } } - /** + /*z * 获取组合任务大小,使用该方式获取到的组合任务大小,子任务不需要再重新获取文件大小 */ private void getGroupSize() { @@ -106,6 +108,7 @@ public class HttpGroupInfoTask implements IInfoTask { cloneHeader(dTaskWrapper); HttpFileInfoTask infoTask = new HttpFileInfoTask(dTaskWrapper); infoTask.setCallback(subCallback); + mPool.execute(infoTask); } } }).start(); diff --git a/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDGLoader.java b/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDGLoader.java new file mode 100644 index 00000000..c18c788f --- /dev/null +++ b/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDGLoader.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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.arialyy.aria.http.download; + +import android.os.Looper; +import com.arialyy.aria.core.common.AbsEntity; +import com.arialyy.aria.core.common.CompleteInfo; +import com.arialyy.aria.core.download.DTaskWrapper; +import com.arialyy.aria.core.download.DownloadEntity; +import com.arialyy.aria.core.group.AbsGroupLoader; +import com.arialyy.aria.core.group.AbsSubDLoadUtil; +import com.arialyy.aria.core.listener.IEventListener; +import com.arialyy.aria.core.loader.IInfoTask; +import com.arialyy.aria.core.wrapper.AbsTaskWrapper; +import com.arialyy.aria.exception.BaseException; + +/** + * http 组合任务加载器 + */ +final class HttpDGLoader extends AbsGroupLoader { + HttpDGLoader(AbsTaskWrapper groupWrapper, IEventListener listener) { + super(groupWrapper, listener); + } + + @Override protected void handlerTask(Looper looper) { + if (isBreak()) { + return; + } + mInfoTask.run(); + } + + @Override + protected AbsSubDLoadUtil createSubLoader(DTaskWrapper wrapper, boolean needGetFileInfo) { + return new HttpSubDLoaderUtil(wrapper, getScheduler(), needGetFileInfo); + } + + private void startSub() { + if (isBreak()) { + return; + } + for (DTaskWrapper wrapper : getWrapper().getSubTaskWrapper()) { + DownloadEntity dEntity = wrapper.getEntity(); + startSubLoader(createSubLoader(wrapper, dEntity.getFileSize() < 0)); + } + } + + @Override public void addComponent(IInfoTask infoTask) { + mInfoTask = infoTask; + mInfoTask.setCallback(new IInfoTask.Callback() { + @Override public void onSucceed(String key, CompleteInfo info) { + startSub(); + } + + @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { + mListener.onFail(needRetry, e); + } + }); + } +} diff --git a/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDGLoaderUtil.java b/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDGLoaderUtil.java new file mode 100644 index 00000000..c53f07ad --- /dev/null +++ b/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDGLoaderUtil.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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.arialyy.aria.http.download; + +import com.arialyy.aria.core.download.DGTaskWrapper; +import com.arialyy.aria.core.group.AbsGroupLoader; +import com.arialyy.aria.core.group.AbsGroupLoaderUtil; +import com.arialyy.aria.core.listener.DownloadGroupListener; +import com.arialyy.aria.core.listener.IEventListener; +import com.arialyy.aria.core.loader.LoaderStructure; +import com.arialyy.aria.core.wrapper.AbsTaskWrapper; +import com.arialyy.aria.http.HttpTaskOption; + +/** + * Created by AriaL on 2017/6/30. + * 任务组下载工具 + */ +public final class HttpDGLoaderUtil extends AbsGroupLoaderUtil { + + public HttpDGLoaderUtil(AbsTaskWrapper taskWrapper, IEventListener listener) { + super(taskWrapper, listener); + taskWrapper.generateTaskOption(HttpTaskOption.class); + } + + @Override protected AbsGroupLoader getLoader() { + return mLoader == null ? new HttpDGLoader(getTaskWrapper(), getListener()) : mLoader; + } + + @Override protected LoaderStructure buildLoaderStructure() { + LoaderStructure structure = new LoaderStructure(); + structure.addComponent(new HttpDGInfoTask((DGTaskWrapper) getTaskWrapper(), + (DownloadGroupListener) getListener())); + structure.accept(getLoader()); + return structure; + } +} \ No newline at end of file diff --git a/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDLoaderAdapter.java b/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDLoaderAdapter.java deleted file mode 100644 index 2510958a..00000000 --- a/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDLoaderAdapter.java +++ /dev/null @@ -1,100 +0,0 @@ -///* -// * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) -// * -// * 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.arialyy.aria.http.download; -// -//import com.arialyy.aria.core.TaskRecord; -//import com.arialyy.aria.core.common.RecordHandler; -//import com.arialyy.aria.core.common.SubThreadConfig; -//import com.arialyy.aria.core.download.DownloadEntity; -//import com.arialyy.aria.core.loader.IRecordHandler; -//import com.arialyy.aria.core.task.AbsNormalLoaderAdapter; -//import com.arialyy.aria.core.task.IThreadTask; -//import com.arialyy.aria.core.task.ThreadTask; -//import com.arialyy.aria.core.wrapper.AbsTaskWrapper; -//import com.arialyy.aria.core.wrapper.ITaskWrapper; -//import com.arialyy.aria.http.HttpRecordHandler; -//import com.arialyy.aria.util.ALog; -//import com.arialyy.aria.util.BufferedRandomAccessFile; -//import com.arialyy.aria.util.FileUtil; -//import java.io.File; -//import java.io.IOException; -// -///** -// * @Author lyy -// * @Date 2019-09-21 -// */ -//final class HttpDLoaderAdapter extends AbsNormalLoaderAdapter { -// HttpDLoaderAdapter(ITaskWrapper wrapper) { -// super(wrapper); -// } -// -// @Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) { -// if (!record.isBlock) { -// if (getTempFile().exists()) { -// FileUtil.deleteFile(getTempFile()); -// } -// } else { -// for (int i = 0; i < totalThreadNum; i++) { -// File blockFile = -// new File(String.format(IRecordHandler.SUB_PATH, getTempFile().getPath(), i)); -// if (blockFile.exists()) { -// ALog.d(TAG, String.format("分块【%s】已经存在,将删除该分块", i)); -// FileUtil.deleteFile(blockFile); -// } -// } -// } -// BufferedRandomAccessFile file = null; -// try { -// if (totalThreadNum > 1 && !record.isBlock) { -// file = new BufferedRandomAccessFile(new File(getTempFile().getPath()), "rwd", 8192); -// //设置文件长度 -// file.setLength(getEntity().getFileSize()); -// } -// return true; -// } catch (IOException e) { -// e.printStackTrace(); -// ALog.e(TAG, String.format("下载失败,filePath: %s, url: %s", getEntity().getFilePath(), -// getEntity().getUrl())); -// } finally { -// if (file != null) { -// try { -// file.close(); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// } -// } -// return false; -// } -// -// @Override public IThreadTask createThreadTask(SubThreadConfig config) { -// ThreadTask task = new ThreadTask(config); -// HttpDThreadTaskAdapter adapter = new HttpDThreadTaskAdapter(config); -// task.setAdapter(adapter); -// return task; -// } -// -// @Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) { -// RecordHandler recordHandler = new RecordHandler(wrapper); -// HttpRecordHandler adapter = new HttpRecordHandler(wrapper); -// recordHandler.setAdapter(adapter); -// return recordHandler; -// } -// -// private DownloadEntity getEntity() { -// return (DownloadEntity) getWrapper().getEntity(); -// } -//} diff --git a/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDLoaderUtil.java b/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDLoaderUtil.java index 846ebedd..7843c596 100644 --- a/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDLoaderUtil.java +++ b/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpDLoaderUtil.java @@ -17,11 +17,11 @@ package com.arialyy.aria.http.download; import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.listener.IEventListener; -import com.arialyy.aria.core.loader.AbsLoader; +import com.arialyy.aria.core.loader.AbsNormalLoader; import com.arialyy.aria.core.loader.AbsNormalLoaderUtil; import com.arialyy.aria.core.loader.LoaderStructure; import com.arialyy.aria.core.loader.NormalLoader; -import com.arialyy.aria.core.loader.ThreadStateManager; +import com.arialyy.aria.core.loader.NormalThreadStateManager; import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.http.HttpFileInfoTask; import com.arialyy.aria.http.HttpRecordHandler; @@ -31,20 +31,20 @@ import com.arialyy.aria.http.HttpTaskOption; * @Author lyy * @Date 2019-09-21 */ -public class HttpDLoaderUtil extends AbsNormalLoaderUtil { +public final class HttpDLoaderUtil extends AbsNormalLoaderUtil { public HttpDLoaderUtil(AbsTaskWrapper wrapper, IEventListener listener) { super(wrapper, listener); wrapper.generateTaskOption(HttpTaskOption.class); } - @Override public AbsLoader getLoader() { + @Override public AbsNormalLoader getLoader() { return mLoader == null ? new NormalLoader(getTaskWrapper(), getListener()) : mLoader; } - public LoaderStructure getLoaderStructure() { + public LoaderStructure BuildLoaderStructure() { LoaderStructure structure = new LoaderStructure(); structure.addComponent(new HttpRecordHandler(getTaskWrapper())) - .addComponent(new ThreadStateManager(getListener())) + .addComponent(new NormalThreadStateManager(getListener())) .addComponent(new HttpFileInfoTask((DTaskWrapper) getTaskWrapper())) .addComponent(new HttpDTTBuilder(getTaskWrapper())); structure.accept(getLoader()); diff --git a/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpSubDLoaderUtil.java b/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpSubDLoaderUtil.java index 03c5117e..0e4d54d9 100644 --- a/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpSubDLoaderUtil.java +++ b/HttpComponent/src/main/java/com/arialyy/aria/http/download/HttpSubDLoaderUtil.java @@ -16,52 +16,41 @@ package com.arialyy.aria.http.download; import android.os.Handler; -import com.arialyy.aria.core.common.AbsEntity; -import com.arialyy.aria.core.common.CompleteInfo; import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.group.AbsSubDLoadUtil; -import com.arialyy.aria.core.group.ChildDLoadListener; -import com.arialyy.aria.core.inf.OnFileInfoCallback; -import com.arialyy.aria.core.listener.ISchedulers; -import com.arialyy.aria.core.loader.NormalLoader; -import com.arialyy.aria.exception.BaseException; +import com.arialyy.aria.core.loader.LoaderStructure; +import com.arialyy.aria.core.loader.SubLoader; import com.arialyy.aria.http.HttpFileInfoTask; +import com.arialyy.aria.http.HttpRecordHandler; /** * @Author lyy * @Date 2019-09-28 */ -class HttpSubDLoaderUtil extends AbsSubDLoadUtil { +final class HttpSubDLoaderUtil extends AbsSubDLoadUtil { /** * @param schedulers 调度器 * @param needGetInfo {@code true} 需要获取文件信息。{@code false} 不需要获取文件信息 */ - HttpSubDLoaderUtil(Handler schedulers, DTaskWrapper taskWrapper, boolean needGetInfo) { - super(schedulers, taskWrapper, needGetInfo); + HttpSubDLoaderUtil(DTaskWrapper taskWrapper, Handler schedulers, boolean needGetInfo) { + super(taskWrapper, schedulers, needGetInfo); } - @Override protected NormalLoader createLoader(ChildDLoadListener listener, DTaskWrapper wrapper) { - NormalLoader loader = new NormalLoader(listener, wrapper); - HttpDLoaderAdapter adapter = new HttpDLoaderAdapter(wrapper); - loader.setAdapter(adapter); - return loader; + @Override protected SubLoader getLoader() { + if (mDLoader == null) { + mDLoader = new SubLoader(getWrapper(), getSchedulers()); + mDLoader.setNeedGetInfo(isNeedGetInfo()); + } + return mDLoader; } - @Override public void start() { - if (isNeedGetInfo()) { - new Thread(new HttpFileInfoTask(getWrapper(), new OnFileInfoCallback() { - - @Override public void onComplete(String url, CompleteInfo info) { - getDownloader().start(); - } - - @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { - getSchedulers().obtainMessage(ISchedulers.FAIL, HttpSubDLoaderUtil.this).sendToTarget(); - } - })).start(); - } else { - getDownloader().start(); - } + @Override protected LoaderStructure buildLoaderStructure() { + LoaderStructure structure = new LoaderStructure(); + structure.addComponent(new HttpRecordHandler(getWrapper())) + .addComponent(new HttpDTTBuilder(getWrapper())) + .addComponent(new HttpFileInfoTask(getWrapper())); + structure.accept(getLoader()); + return structure; } } diff --git a/HttpComponent/src/main/java/com/arialyy/aria/http/upload/HttpULoaderUtil.java b/HttpComponent/src/main/java/com/arialyy/aria/http/upload/HttpULoaderUtil.java index 9db99f17..3f3faaa2 100644 --- a/HttpComponent/src/main/java/com/arialyy/aria/http/upload/HttpULoaderUtil.java +++ b/HttpComponent/src/main/java/com/arialyy/aria/http/upload/HttpULoaderUtil.java @@ -15,35 +15,39 @@ */ package com.arialyy.aria.http.upload; +import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.listener.IEventListener; -import com.arialyy.aria.core.loader.AbsLoader; +import com.arialyy.aria.core.loader.AbsNormalLoader; import com.arialyy.aria.core.loader.AbsNormalLoaderUtil; +import com.arialyy.aria.core.loader.LoaderStructure; import com.arialyy.aria.core.loader.NormalLoader; +import com.arialyy.aria.core.loader.NormalThreadStateManager; import com.arialyy.aria.core.wrapper.AbsTaskWrapper; +import com.arialyy.aria.http.HttpFileInfoTask; +import com.arialyy.aria.http.HttpRecordHandler; import com.arialyy.aria.http.HttpTaskOption; /** * @Author lyy * @Date 2019-09-19 */ -public class HttpULoaderUtil extends AbsNormalLoaderUtil { +public final class HttpULoaderUtil extends AbsNormalLoaderUtil { public HttpULoaderUtil(AbsTaskWrapper wrapper, IEventListener listener) { super(wrapper, listener); wrapper.generateTaskOption(HttpTaskOption.class); } - @Override protected AbsLoader createLoader() { - NormalLoader loader = new NormalLoader(getListener(), getTaskWrapper()); - HttpULoaderAdapter adapter = new HttpULoaderAdapter(getTaskWrapper()); - loader.setAdapter(adapter); - return loader; + @Override public AbsNormalLoader getLoader() { + return mLoader == null ? new NormalLoader(getTaskWrapper(), getListener()) : mLoader; } - @Override protected Runnable createInfoThread() { - return new Runnable() { - @Override public void run() { - getLoader().start(); - } - }; + @Override public LoaderStructure BuildLoaderStructure() { + LoaderStructure structure = new LoaderStructure(); + structure.addComponent(new HttpRecordHandler(getTaskWrapper())) + .addComponent(new NormalThreadStateManager(getListener())) + .addComponent(new HttpFileInfoTask((DTaskWrapper) getTaskWrapper())) + .addComponent(new HttpUTTBuilder(getTaskWrapper())); + structure.accept(getLoader()); + return structure; } } diff --git a/HttpComponent/src/main/java/com/arialyy/aria/http/upload/HttpULoaderAdapter.java b/HttpComponent/src/main/java/com/arialyy/aria/http/upload/HttpUTTBuilder.java similarity index 50% rename from HttpComponent/src/main/java/com/arialyy/aria/http/upload/HttpULoaderAdapter.java rename to HttpComponent/src/main/java/com/arialyy/aria/http/upload/HttpUTTBuilder.java index d22a0d28..1e6ef897 100644 --- a/HttpComponent/src/main/java/com/arialyy/aria/http/upload/HttpULoaderAdapter.java +++ b/HttpComponent/src/main/java/com/arialyy/aria/http/upload/HttpUTTBuilder.java @@ -16,40 +16,26 @@ package com.arialyy.aria.http.upload; import com.arialyy.aria.core.TaskRecord; -import com.arialyy.aria.core.common.RecordHandler; import com.arialyy.aria.core.common.SubThreadConfig; -import com.arialyy.aria.core.loader.IRecordHandler; -import com.arialyy.aria.core.task.AbsNormalLoaderAdapter; -import com.arialyy.aria.core.task.IThreadTask; -import com.arialyy.aria.core.task.ThreadTask; +import com.arialyy.aria.core.loader.AbsNormalTTBuilder; +import com.arialyy.aria.core.task.IThreadTaskAdapter; import com.arialyy.aria.core.wrapper.AbsTaskWrapper; -import com.arialyy.aria.core.wrapper.ITaskWrapper; -import com.arialyy.aria.http.HttpRecordHandler; /** * @Author lyy * @Date 2019-09-19 */ -final class HttpULoaderAdapter extends AbsNormalLoaderAdapter { - public HttpULoaderAdapter(ITaskWrapper wrapper) { - super(wrapper); - } +final class HttpUTTBuilder extends AbsNormalTTBuilder { - @Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) { - return true; + HttpUTTBuilder(AbsTaskWrapper wrapper) { + super(wrapper); } - @Override public IThreadTask createThreadTask(SubThreadConfig config) { - ThreadTask task = new ThreadTask(config); - HttpUThreadTaskAdapter adapter = new HttpUThreadTaskAdapter(config); - task.setAdapter(adapter); - return task; + @Override public IThreadTaskAdapter getAdapter(SubThreadConfig config) { + return new HttpUThreadTaskAdapter(config); } - @Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) { - RecordHandler recordHandler = new RecordHandler(wrapper); - HttpRecordHandler adapter = new HttpRecordHandler(wrapper); - recordHandler.setAdapter(adapter); - return recordHandler; + @Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) { + return true; } } diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/BaseM3U8Loader.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/BaseM3U8Loader.java index 8ef1e78e..c24488dc 100644 --- a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/BaseM3U8Loader.java +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/BaseM3U8Loader.java @@ -16,14 +16,11 @@ package com.arialyy.aria.m3u8; import android.text.TextUtils; -import com.arialyy.aria.core.common.RecordHandler; import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.M3U8Entity; -import com.arialyy.aria.core.loader.IRecordHandler; import com.arialyy.aria.core.listener.IEventListener; -import com.arialyy.aria.core.loader.AbsLoader; -import com.arialyy.aria.core.wrapper.AbsTaskWrapper; +import com.arialyy.aria.core.loader.AbsNormalLoader; import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.FileUtil; import java.io.BufferedReader; @@ -35,11 +32,11 @@ import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.Charset; -public abstract class BaseM3U8Loader extends AbsLoader { +public abstract class BaseM3U8Loader extends AbsNormalLoader { protected M3U8TaskOption mM3U8Option; - public BaseM3U8Loader(IEventListener listener, DTaskWrapper wrapper) { - super(listener, wrapper); + public BaseM3U8Loader(DTaskWrapper wrapper, IEventListener listener) { + super(wrapper, listener); mM3U8Option = (M3U8TaskOption) wrapper.getM3u8Option(); mTempFile = new File(wrapper.getEntity().getFilePath()); } @@ -58,7 +55,7 @@ public abstract class BaseM3U8Loader extends AbsLoader { return String.format("%s/%s.ts", dirCache, threadId); } - protected String getCacheDir() { + public String getCacheDir() { String cacheDir = mM3U8Option.getCacheDir(); if (TextUtils.isEmpty(cacheDir)) { cacheDir = FileUtil.getTsCacheDir(getEntity().getFilePath(), mM3U8Option.getBandWidth()); @@ -74,7 +71,7 @@ public abstract class BaseM3U8Loader extends AbsLoader { */ public boolean generateIndexFile(boolean isLive) { File tempFile = - new File(String.format(M3U8InfoThread.M3U8_INDEX_FORMAT, getEntity().getFilePath())); + new File(String.format(M3U8InfoTask.M3U8_INDEX_FORMAT, getEntity().getFilePath())); if (!tempFile.exists()) { ALog.e(TAG, "源索引文件不存在"); return false; @@ -136,17 +133,10 @@ public abstract class BaseM3U8Loader extends AbsLoader { return false; } - @Override public long getCurrentLocation() { + @Override public long getCurrentProgress() { return isRunning() ? getStateManager().getCurrentProgress() : getEntity().getCurrentProgress(); } - @Override protected IRecordHandler getRecordHandler(AbsTaskWrapper wrapper) { - RecordHandler handler = new RecordHandler(wrapper); - M3U8RecordHandler adapter = new M3U8RecordHandler((DTaskWrapper) wrapper); - handler.setAdapter(adapter); - return handler; - } - protected DownloadEntity getEntity() { return (DownloadEntity) mTaskWrapper.getEntity(); } diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/IdGenerator.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/IdGenerator.java index 28955696..8543a82d 100644 --- a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/IdGenerator.java +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/IdGenerator.java @@ -1,6 +1,6 @@ package com.arialyy.aria.m3u8; -public class IdGenerator { +public final class IdGenerator { /** * SnowFlake算法 64位Long类型生成唯一ID 第一位0,表明正数 2-42,41位,表示毫秒时间戳差值,起始值自定义 * 43-52,10位,机器编号,5位数据中心编号,5位进程编号 53-64,12位,毫秒内计数器 本机内存生成,性能高 diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8InfoThread.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8InfoTask.java similarity index 94% rename from M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8InfoThread.java rename to M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8InfoTask.java index 7d3ef2d4..2b1799ed 100644 --- a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8InfoThread.java +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8InfoTask.java @@ -24,7 +24,8 @@ import com.arialyy.aria.core.common.CompleteInfo; import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.M3U8Entity; -import com.arialyy.aria.core.inf.OnFileInfoCallback; +import com.arialyy.aria.core.loader.IInfoTask; +import com.arialyy.aria.core.loader.ILoaderVisitor; import com.arialyy.aria.core.processor.IBandWidthUrlConverter; import com.arialyy.aria.core.processor.IKeyUrlConverter; import com.arialyy.aria.core.wrapper.AbsTaskWrapper; @@ -59,30 +60,33 @@ import java.util.regex.Pattern; * https://www.cnblogs.com/renhui/p/10351870.html * https://blog.csdn.net/Guofengpu/article/details/54922865 */ -final public class M3U8InfoThread implements Runnable { +final public class M3U8InfoTask implements IInfoTask { public static final String M3U8_INDEX_FORMAT = "%s.index"; private final String TAG = "M3U8InfoThread"; private DownloadEntity mEntity; private DTaskWrapper mTaskWrapper; private int mConnectTimeOut; - private OnFileInfoCallback onFileInfoCallback; private OnGetLivePeerCallback onGetPeerCallback; private HttpTaskOption mHttpOption; private M3U8TaskOption mM3U8Option; + private Callback mCallback; /** * 是否停止获取切片信息,{@code true}停止获取切片信息 */ private boolean isStop = false; + @Override public void accept(ILoaderVisitor visitor) { + visitor.addComponent(this); + } + public interface OnGetLivePeerCallback { void onGetPeer(String url, String extInf); } - public M3U8InfoThread(DTaskWrapper taskWrapper, OnFileInfoCallback callback) { + public M3U8InfoTask(DTaskWrapper taskWrapper) { this.mTaskWrapper = taskWrapper; mEntity = taskWrapper.getEntity(); mConnectTimeOut = AriaConfig.getInstance().getDConfig().getConnectTimeOut(); - onFileInfoCallback = callback; mHttpOption = (HttpTaskOption) taskWrapper.getTaskOption(); mM3U8Option = (M3U8TaskOption) taskWrapper.getM3u8Option(); mEntity.getM3U8Entity().setLive(mTaskWrapper.getRequestType() == AbsTaskWrapper.M3U8_LIVE); @@ -108,6 +112,10 @@ final public class M3U8InfoThread implements Runnable { } } + @Override public void setCallback(Callback callback) { + mCallback = callback; + } + private void handleConnect(HttpURLConnection conn) throws IOException { int code = conn.getResponseCode(); if (code == HttpURLConnection.HTTP_OK) { @@ -191,7 +199,7 @@ final public class M3U8InfoThread implements Runnable { CompleteInfo info = new CompleteInfo(); info.obj = extInf; - onFileInfoCallback.onComplete(mEntity.getKey(), info); + mCallback.onSucceed(mEntity.getKey(), info); if (fos != null) { fos.close(); } @@ -255,9 +263,9 @@ final public class M3U8InfoThread implements Runnable { m3U8Entity.keyUrl) + ".key"; } else if (param.startsWith("IV")) { m3U8Entity.iv = param.split("=")[1]; - }else if (param.startsWith("KEYFORMAT")){ + } else if (param.startsWith("KEYFORMAT")) { m3U8Entity.keyFormat = param.split("=")[1]; - }else if (param.startsWith("KEYFORMATVERSIONS")){ + } else if (param.startsWith("KEYFORMATVERSIONS")) { m3U8Entity.keyFormatVersion = param.split("=")[1]; } } @@ -282,8 +290,8 @@ final public class M3U8InfoThread implements Runnable { private void handleUrlReTurn(HttpURLConnection conn, String newUrl) throws IOException { ALog.d(TAG, "30x跳转,新url为【" + newUrl + "】"); if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null")) { - if (onFileInfoCallback != null) { - onFileInfoCallback.onFail(mEntity, new TaskException(TAG, "获取重定向链接失败"), false); + if (mCallback != null) { + mCallback.onFail(mEntity, new TaskException(TAG, "获取重定向链接失败"), false); } return; } @@ -341,7 +349,7 @@ final public class M3U8InfoThread implements Runnable { } private void failDownload(String errorInfo, boolean needRetry) { - onFileInfoCallback.onFail(mEntity, new M3U8Exception(TAG, errorInfo), needRetry); + mCallback.onFail(mEntity, new M3U8Exception(TAG, errorInfo), needRetry); } /** @@ -364,7 +372,7 @@ final public class M3U8InfoThread implements Runnable { if (keyUrlConverter != null) { keyUrl = keyUrlConverter.convert(keyUrl); } - if (TextUtils.isEmpty(keyUrl)){ + if (TextUtils.isEmpty(keyUrl)) { ALog.e(TAG, "m3u8密钥key url 为空"); return; } diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8Listener.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8Listener.java index 61cc43ed..541dbf44 100644 --- a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8Listener.java +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8Listener.java @@ -29,7 +29,7 @@ import com.arialyy.aria.util.CommonUtil; /** * 下载监听类 */ -public class M3U8Listener extends BaseDListener implements IDLoadListener { +public final class M3U8Listener extends BaseDListener implements IDLoadListener { public M3U8Listener(AbsTask task, Handler outHandler) { super(task, outHandler); diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8RecordHandler.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8RecordHandler.java index 4eb15411..507dcb05 100644 --- a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8RecordHandler.java +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8RecordHandler.java @@ -33,10 +33,10 @@ import java.util.ArrayList; * @Author lyy * @Date 2019-09-24 */ -public class M3U8RecordHandler extends RecordHandler { +public final class M3U8RecordHandler extends RecordHandler { private M3U8TaskOption mOption; - M3U8RecordHandler(DTaskWrapper wrapper) { + public M3U8RecordHandler(DTaskWrapper wrapper) { super(wrapper); mOption = (M3U8TaskOption) wrapper.getM3u8Option(); } @@ -64,7 +64,7 @@ public class M3U8RecordHandler extends RecordHandler { // 重新下载所有切片 boolean reDownload = (m3U8Entity.getPeerNum() <= 0 || (mOption.isGenerateIndexFile() && !new File( - String.format(M3U8InfoThread.M3U8_INDEX_FORMAT, getEntity().getFilePath())).exists())); + String.format(M3U8InfoTask.M3U8_INDEX_FORMAT, getEntity().getFilePath())).exists())); for (ThreadRecord record : mTaskRecord.threadRecords) { File temp = new File(BaseM3U8Loader.getTsFilePath(cacheDir, record.threadId)); diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8TaskOption.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8TaskOption.java index b6c35052..37c36ae8 100644 --- a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8TaskOption.java +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8TaskOption.java @@ -27,7 +27,7 @@ import java.util.List; /** * m3u8任务配信息 */ -public class M3U8TaskOption implements ITaskOption { +public final class M3U8TaskOption implements ITaskOption { /** * 所有ts文件的下载地址 diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8ThreadTaskAdapter.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8ThreadTaskAdapter.java index 39d95a3d..82f5d517 100644 --- a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8ThreadTaskAdapter.java +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/M3U8ThreadTaskAdapter.java @@ -43,7 +43,7 @@ import java.util.Set; /** * Created by lyy on 2017/1/18. 下载线程 */ -public class M3U8ThreadTaskAdapter extends AbsThreadTaskAdapter { +public final class M3U8ThreadTaskAdapter extends AbsThreadTaskAdapter { private final String TAG = "M3U8ThreadTask"; private HttpTaskOption mHttpTaskOption; diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/live/LiveStateManager.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/live/LiveStateManager.java new file mode 100644 index 00000000..62b27892 --- /dev/null +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/live/LiveStateManager.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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.arialyy.aria.m3u8.live; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import com.arialyy.aria.core.TaskRecord; +import com.arialyy.aria.core.download.DTaskWrapper; +import com.arialyy.aria.core.inf.IThreadStateManager; +import com.arialyy.aria.core.listener.IEventListener; +import com.arialyy.aria.core.listener.ISchedulers; +import com.arialyy.aria.core.loader.ILoaderVisitor; +import com.arialyy.aria.m3u8.M3U8Listener; +import com.arialyy.aria.m3u8.M3U8TaskOption; +import com.arialyy.aria.util.ALog; +import com.arialyy.aria.util.CommonUtil; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.Charset; + +import static com.arialyy.aria.m3u8.M3U8InfoTask.M3U8_INDEX_FORMAT; + +final class LiveStateManager implements IThreadStateManager { + private final String TAG = CommonUtil.getClassName(getClass()); + + private M3U8Listener mListener; + private long mProgress; //当前总进度 + private Looper mLooper; + private DTaskWrapper mTaskWrapper; + private M3U8TaskOption mM3U8Option; + private FileOutputStream mIndexFos; + private M3U8LiveLoader mLoader; + + /** + * @param listener 任务事件 + */ + LiveStateManager(DTaskWrapper wrapper, IEventListener listener) { + mTaskWrapper = wrapper; + mListener = (M3U8Listener) listener; + mM3U8Option = (M3U8TaskOption) mTaskWrapper.getM3u8Option(); + } + + private Handler.Callback mCallback = new Handler.Callback() { + @Override public boolean handleMessage(Message msg) { + int peerIndex = msg.getData().getInt(ISchedulers.DATA_M3U8_PEER_INDEX); + switch (msg.what) { + case STATE_STOP: + if (mLoader.isBreak()) { + ALog.d(TAG, "任务停止"); + quitLooper(); + } + break; + case STATE_CANCEL: + if (mLoader.isBreak()) { + ALog.d(TAG, "任务取消"); + quitLooper(); + } + break; + case STATE_COMPLETE: + mLoader.notifyLock(true, peerIndex); + if (mM3U8Option.isGenerateIndexFile() && !mLoader.isBreak()) { + addExtInf(mLoader.getCurExtInfo().url, mLoader.getCurExtInfo().extInf); + } + mListener.onPeerComplete(mTaskWrapper.getKey(), + msg.getData().getString(ISchedulers.DATA_M3U8_PEER_PATH), peerIndex); + break; + case STATE_RUNNING: + mProgress += (long) msg.obj; + break; + case STATE_FAIL: + mLoader.notifyLock(false, peerIndex); + mListener.onPeerFail(mTaskWrapper.getKey(), + msg.getData().getString(ISchedulers.DATA_M3U8_PEER_PATH), peerIndex); + break; + } + return true; + } + }; + + void setLoader(M3U8LiveLoader loader) { + mLoader = loader; + } + + /** + * 退出looper循环 + */ + private void quitLooper() { + ALog.d(TAG, "quitLooper"); + mLooper.quit(); + if (mIndexFos != null) { + try { + mIndexFos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * 给索引文件添加extInfo信息 + */ + private void addExtInf(String url, String extInf) { + File indexFile = + new File(String.format(M3U8_INDEX_FORMAT, mTaskWrapper.getEntity().getFilePath())); + if (!indexFile.exists()) { + ALog.e(TAG, String.format("索引文件【%s】不存在,添加peer的extInf失败", indexFile.getPath())); + return; + } + try { + if (mIndexFos == null) { + mIndexFos = new FileOutputStream(indexFile, true); + } + mIndexFos.write(extInf.concat("\r\n").getBytes(Charset.forName("UTF-8"))); + mIndexFos.write(url.concat("\r\n").getBytes(Charset.forName("UTF-8"))); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override public boolean isFail() { + return false; + } + + @Override public boolean isComplete() { + return false; + } + + @Override public long getCurrentProgress() { + return mProgress; + } + + @Override public void setLooper(TaskRecord taskRecord, Looper looper) { + mLooper = looper; + } + + @Override public Handler.Callback getHandlerCallback() { + return mCallback; + } + + @Override public void accept(ILoaderVisitor visitor) { + visitor.addComponent(this); + } +} diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/live/M3U8LiveLoader.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/live/M3U8LiveLoader.java index 81af7931..72cbb938 100644 --- a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/live/M3U8LiveLoader.java +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/live/M3U8LiveLoader.java @@ -17,42 +17,46 @@ package com.arialyy.aria.m3u8.live; import android.os.Handler; import android.os.Looper; -import android.os.Message; -import com.arialyy.aria.core.TaskRecord; +import android.text.TextUtils; import com.arialyy.aria.core.ThreadRecord; +import com.arialyy.aria.core.common.AbsEntity; +import com.arialyy.aria.core.common.CompleteInfo; import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.download.DTaskWrapper; -import com.arialyy.aria.core.inf.IThreadState; -import com.arialyy.aria.core.listener.IEventListener; -import com.arialyy.aria.core.listener.ISchedulers; +import com.arialyy.aria.core.inf.IThreadStateManager; +import com.arialyy.aria.core.loader.IInfoTask; +import com.arialyy.aria.core.loader.IRecordHandler; +import com.arialyy.aria.core.loader.IThreadTaskBuilder; import com.arialyy.aria.core.manager.ThreadTaskManager; +import com.arialyy.aria.core.processor.ILiveTsUrlConverter; import com.arialyy.aria.core.processor.ITsMergeHandler; import com.arialyy.aria.core.task.ThreadTask; +import com.arialyy.aria.exception.BaseException; +import com.arialyy.aria.exception.M3U8Exception; +import com.arialyy.aria.exception.TaskException; import com.arialyy.aria.m3u8.BaseM3U8Loader; import com.arialyy.aria.m3u8.IdGenerator; +import com.arialyy.aria.m3u8.M3U8InfoTask; import com.arialyy.aria.m3u8.M3U8Listener; import com.arialyy.aria.m3u8.M3U8TaskOption; import com.arialyy.aria.m3u8.M3U8ThreadTaskAdapter; import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.FileUtil; import java.io.File; -import java.io.FileOutputStream; import java.io.FilenameFilter; -import java.io.IOException; -import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; -import static com.arialyy.aria.m3u8.M3U8InfoThread.M3U8_INDEX_FORMAT; - /** * M3U8点播文件下载器 */ -public class M3U8LiveLoader extends BaseM3U8Loader { +final class M3U8LiveLoader extends BaseM3U8Loader { /** * 最大执行数 */ @@ -63,28 +67,34 @@ public class M3U8LiveLoader extends BaseM3U8Loader { private Condition mCondition = LOCK.newCondition(); private LinkedBlockingQueue mPeerQueue = new LinkedBlockingQueue<>(); private ExtInfo mCurExtInfo; - private FileOutputStream mIndexFos; + private LiveStateManager mManager; + private M3U8InfoTask mInfoTask; + private ScheduledThreadPoolExecutor mTimer; + private List mPeerUrls = new ArrayList<>(); + private Looper mLooper; - M3U8LiveLoader(M3U8Listener listener, DTaskWrapper wrapper) { - super(listener, wrapper); + M3U8LiveLoader(DTaskWrapper wrapper, M3U8Listener listener) { + super(wrapper, listener); if (((M3U8TaskOption) wrapper.getM3u8Option()).isGenerateIndexFile()) { ALog.i(TAG, "直播文件下载,创建索引文件的操作将导致只能同时下载一个切片"); EXEC_MAX_NUM = 1; } } - @Override protected IThreadState createStateManager(Looper looper) { - LiveStateManager manager = new LiveStateManager(looper, mListener); - mStateHandler = new Handler(looper, manager); - return manager; + ExtInfo getCurExtInfo() { + return mCurExtInfo; } - void offerPeer(ExtInfo extInfo) { + private void offerPeer(ExtInfo extInfo) { mPeerQueue.offer(extInfo); } - @Override protected void handleTask() { - + @Override protected void handleTask(Looper looper) { + if (isBreak()) { + return; + } + mLooper = looper; + startLoaderLiveInfo(); new Thread(new Runnable() { @Override public void run() { String cacheDir = getCacheDir(); @@ -99,7 +109,7 @@ public class M3U8LiveLoader extends BaseM3U8Loader { } mCurExtInfo = extInfo; ThreadTask task = createThreadTask(cacheDir, index, extInfo.url); - getTaskList().put(index, task); + getTaskList().add(task); mFlagQueue.offer(startThreadTask(task, task.getConfig().peerIndex)); index++; } @@ -120,7 +130,7 @@ public class M3U8LiveLoader extends BaseM3U8Loader { return mTempFile.length(); } - private void notifyLock(boolean success, int peerId) { + void notifyLock(boolean success, int peerId) { try { LOCK.lock(); long id = mFlagQueue.take(); @@ -137,17 +147,6 @@ public class M3U8LiveLoader extends BaseM3U8Loader { } } - @Override protected void onPostStop() { - super.onPostStop(); - if (mIndexFos != null) { - try { - mIndexFos.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - /** * 启动线程任务 * @@ -155,7 +154,7 @@ public class M3U8LiveLoader extends BaseM3U8Loader { */ private long startThreadTask(ThreadTask task, int indexId) { ThreadTaskManager.getInstance().startThread(mTaskWrapper.getKey(), task); - ((M3U8Listener) mListener).onPeerStart(mTaskWrapper.getKey(), + ((M3U8Listener) getListener()).onPeerStart(mTaskWrapper.getKey(), task.getConfig().tempFile.getPath(), indexId); return IdGenerator.getInstance().nextId(); @@ -196,7 +195,7 @@ public class M3U8LiveLoader extends BaseM3U8Loader { * * @return {@code true} 合并成功,{@code false}合并失败 */ - boolean mergeFile() { + private boolean mergeFile() { ITsMergeHandler mergeHandler = mM3U8Option.getMergeHandler(); String cacheDir = getCacheDir(); List partPath = new ArrayList<>(); @@ -234,101 +233,117 @@ public class M3U8LiveLoader extends BaseM3U8Loader { } } - /** - * M3U8线程状态管理,直播不处理停止状态、删除、失败的状态 - */ - private class LiveStateManager implements IThreadState { - private final String TAG = "M3U8ThreadStateManager"; + @Override public void addComponent(IRecordHandler recordHandler) { + mRecordHandler = recordHandler; + } - /** - * 任务状态回调 - */ - private M3U8Listener mListener; - private long mProgress; //当前总进度 - private Looper mLooper; + @Override public void addComponent(IInfoTask infoTask) { + mInfoTask = (M3U8InfoTask) infoTask; + mInfoTask.setCallback(new IInfoTask.Callback() { + @Override public void onSucceed(String key, CompleteInfo info) { + ALog.d(TAG, "更新直播的m3u8文件"); + } - /** - * @param listener 任务事件 - */ - LiveStateManager(Looper looper, IEventListener listener) { - mLooper = looper; - mListener = (M3U8Listener) listener; - } + @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { - /** - * 退出looper循环 - */ - private void quitLooper() { - ALog.d(TAG, "quitLooper"); - mLooper.quit(); - } + } + }); - @Override public boolean handleMessage(Message msg) { - int peerIndex = msg.getData().getInt(ISchedulers.DATA_M3U8_PEER_INDEX); - switch (msg.what) { - case STATE_STOP: - if (isBreak()) { - ALog.d(TAG, "任务停止"); - quitLooper(); - } - break; - case STATE_CANCEL: - if (isBreak()) { - ALog.d(TAG, "任务取消"); - quitLooper(); - } - break; - case STATE_COMPLETE: - notifyLock(true, peerIndex); - if (mM3U8Option.isGenerateIndexFile() && !isBreak()) { - addExtInf(mCurExtInfo.url, mCurExtInfo.extInf); + mInfoTask.setOnGetPeerCallback(new M3U8InfoTask.OnGetLivePeerCallback() { + @Override public void onGetPeer(String url, String extInf) { + if (mPeerUrls.contains(url)) { + return; + } + mPeerUrls.add(url); + ILiveTsUrlConverter converter = mM3U8Option.getLiveTsUrlConverter(); + if (converter != null) { + if (TextUtils.isEmpty(mM3U8Option.getBandWidthUrl())) { + url = converter.convert(getEntity().getUrl(), url); + } else { + url = converter.convert(mM3U8Option.getBandWidthUrl(), url); } - mListener.onPeerComplete(mTaskWrapper.getKey(), - msg.getData().getString(ISchedulers.DATA_M3U8_PEER_PATH), peerIndex); - break; - case STATE_RUNNING: - mProgress += (long) msg.obj; - break; - case STATE_FAIL: - notifyLock(false, peerIndex); - mListener.onPeerFail(mTaskWrapper.getKey(), - msg.getData().getString(ISchedulers.DATA_M3U8_PEER_PATH), peerIndex); - break; + } + if (TextUtils.isEmpty(url) || !url.startsWith("http")) { + fail(new M3U8Exception(TAG, String.format("ts地址错误,url:%s", url)), false); + return; + } + offerPeer(new M3U8LiveLoader.ExtInfo(url, extInf)); } - return false; - } + }); + } - /** - * 给索引文件添加extInfo信息 - */ - private void addExtInf(String url, String extInf) { - File indexFile = - new File(String.format(M3U8_INDEX_FORMAT, getEntity().getFilePath())); - if (!indexFile.exists()) { - ALog.e(TAG, String.format("索引文件【%s】不存在,添加peer的extInf失败", indexFile.getPath())); - return; - } - try { - if (mIndexFos == null) { - mIndexFos = new FileOutputStream(indexFile, true); + private void fail(BaseException e, boolean needRetry) { + getListener().onFail(needRetry, e); + handleComplete(); + } + + private void handleComplete() { + if (mInfoTask != null) { + mInfoTask.setStop(true); + closeInfoTimer(); + if (mM3U8Option.isGenerateIndexFile()) { + if (generateIndexFile(true)) { + getListener().onComplete(); + } else { + getListener().onFail(false, new TaskException(TAG, "创建索引文件失败")); } - mIndexFos.write(extInf.concat("\r\n").getBytes(Charset.forName("UTF-8"))); - mIndexFos.write(url.concat("\r\n").getBytes(Charset.forName("UTF-8"))); - } catch (IOException e) { - e.printStackTrace(); + } else if (mM3U8Option.isMergeFile()) { + if (mergeFile()) { + getListener().onComplete(); + } else { + getListener().onFail(false, new M3U8Exception(TAG, "合并文件失败")); + } + } else { + getListener().onComplete(); } } + } - @Override public boolean isFail() { - return false; - } + /** + * 开始循环加载m3u8信息 + */ + private void startLoaderLiveInfo() { + mTimer = new ScheduledThreadPoolExecutor(1); + mTimer.scheduleWithFixedDelay(new Runnable() { + @Override public void run() { + mInfoTask.run(); + } + }, 0, mM3U8Option.getLiveUpdateInterval(), TimeUnit.MILLISECONDS); + } - @Override public boolean isComplete() { - return false; + private void closeInfoTimer() { + if (mTimer != null && !mTimer.isShutdown()) { + mTimer.shutdown(); } + } + + /** + * 需要在{@link #addComponent(IRecordHandler)} 后调用 + */ + @Override public void addComponent(IThreadStateManager threadState) { + mManager = (LiveStateManager) threadState; + mManager.setLooper(mRecordHandler.getRecord(0), mLooper); + mManager.setLoader(this); + mStateHandler = new Handler(mLooper, mManager.getHandlerCallback()); + } + + /** + * @deprecated m3u8 不需要实现这个 + */ + @Deprecated + @Override public void addComponent(IThreadTaskBuilder builder) { + + } - @Override public long getCurrentProgress() { - return mProgress; + @Override protected void checkComponent() { + if (mRecordHandler == null) { + throw new NullPointerException("任务记录组件为空"); + } + if (mInfoTask == null) { + throw new NullPointerException(("文件信息组件为空")); + } + if (mManager == null) { + throw new NullPointerException("任务状态管理组件为空"); } } diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/live/M3U8LiveUtil.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/live/M3U8LiveUtil.java index 17a62bcf..eb7327a5 100644 --- a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/live/M3U8LiveUtil.java +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/live/M3U8LiveUtil.java @@ -15,30 +15,17 @@ */ package com.arialyy.aria.m3u8.live; -import android.text.TextUtils; -import com.arialyy.aria.core.common.AbsEntity; -import com.arialyy.aria.core.common.CompleteInfo; import com.arialyy.aria.core.download.DTaskWrapper; -import com.arialyy.aria.core.inf.OnFileInfoCallback; import com.arialyy.aria.core.listener.IEventListener; -import com.arialyy.aria.core.loader.AbsLoader; import com.arialyy.aria.core.loader.AbsNormalLoaderUtil; -import com.arialyy.aria.core.processor.ILiveTsUrlConverter; +import com.arialyy.aria.core.loader.LoaderStructure; import com.arialyy.aria.core.wrapper.AbsTaskWrapper; -import com.arialyy.aria.exception.BaseException; -import com.arialyy.aria.exception.M3U8Exception; -import com.arialyy.aria.exception.TaskException; import com.arialyy.aria.http.HttpTaskOption; -import com.arialyy.aria.m3u8.M3U8InfoThread; +import com.arialyy.aria.m3u8.M3U8InfoTask; import com.arialyy.aria.m3u8.M3U8Listener; +import com.arialyy.aria.m3u8.M3U8RecordHandler; import com.arialyy.aria.m3u8.M3U8TaskOption; -import com.arialyy.aria.util.ALog; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; +import com.arialyy.aria.util.CommonUtil; /** * M3U8直播文件下载工具,对于直播来说,需要定时更新m3u8文件 @@ -50,12 +37,7 @@ import java.util.concurrent.TimeUnit; * 5、不处理直播切片下载失败的状态 */ public class M3U8LiveUtil extends AbsNormalLoaderUtil { - private final String TAG = "M3U8LiveDownloadUtil"; - private M3U8InfoThread mInfoThread; - private ScheduledThreadPoolExecutor mTimer; - private ExecutorService mInfoPool = Executors.newCachedThreadPool(); - private List mPeerUrls = new ArrayList<>(); - private M3U8TaskOption mM3U8Option; + private final String TAG = CommonUtil.getClassName(getClass()); public M3U8LiveUtil(AbsTaskWrapper wrapper, IEventListener listener) { super(wrapper, listener); @@ -65,117 +47,20 @@ public class M3U8LiveUtil extends AbsNormalLoaderUtil { return (DTaskWrapper) super.getTaskWrapper(); } - @Override protected AbsLoader createLoader() { + @Override public M3U8LiveLoader getLoader() { getTaskWrapper().generateM3u8Option(M3U8TaskOption.class); getTaskWrapper().generateTaskOption(HttpTaskOption.class); - mM3U8Option = (M3U8TaskOption) getTaskWrapper().getM3u8Option(); - return new M3U8LiveLoader((M3U8Listener) getListener(), getTaskWrapper()); - } - - @Override protected Runnable createInfoThread() { - return null; - } - - private Runnable createLiveInfoThread() { - M3U8InfoThread infoThread = - new M3U8InfoThread(getTaskWrapper(), new OnFileInfoCallback() { - @Override public void onComplete(String key, CompleteInfo info) { - ALog.d(TAG, "更新直播的m3u8文件"); - } - - @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { - fail(e, needRetry); - } - }); - infoThread.setOnGetPeerCallback(new M3U8InfoThread.OnGetLivePeerCallback() { - @Override public void onGetPeer(String url, String extInf) { - if (mPeerUrls.contains(url)) { - return; - } - mPeerUrls.add(url); - ILiveTsUrlConverter converter = mM3U8Option.getLiveTsUrlConverter(); - if (converter != null) { - if (TextUtils.isEmpty(mM3U8Option.getBandWidthUrl())) { - url = converter.convert(getTaskWrapper().getEntity().getUrl(), url); - } else { - url = converter.convert(mM3U8Option.getBandWidthUrl(), url); - } - } - if (TextUtils.isEmpty(url) || !url.startsWith("http")) { - fail(new M3U8Exception(TAG, String.format("ts地址错误,url:%s", url)), false); - return; - } - getLoader().offerPeer(new M3U8LiveLoader.ExtInfo(url, extInf)); - } - }); - return infoThread; + return + mLoader == null ? new M3U8LiveLoader(getTaskWrapper(), (M3U8Listener) getListener()) + : (M3U8LiveLoader) mLoader; } - @Override protected void onCancel() { - super.onCancel(); - if (mInfoThread != null) { - mInfoThread.setStop(true); - } - } - - /** - * 对于直播来说是没有停止的,停止就代表完成 - */ - @Override protected void onStop() { - super.onStop(); - handleComplete(); - } - - private void handleComplete() { - if (mInfoThread != null) { - mInfoThread.setStop(true); - closeTimer(); - if (((M3U8TaskOption) getTaskWrapper().getM3u8Option()).isGenerateIndexFile()) { - if (getLoader().generateIndexFile(true)) { - getListener().onComplete(); - } else { - getListener().onFail(false, new TaskException(TAG, "创建索引文件失败")); - } - } else if (mM3U8Option.isMergeFile()) { - if (getLoader().mergeFile()) { - getListener().onComplete(); - } else { - getListener().onFail(false, new M3U8Exception(TAG, "合并文件失败")); - } - } else { - getListener().onComplete(); - } - } - } - - @Override protected void onStart() { - super.onStart(); - startTimer(); - } - - private void startTimer() { - mTimer = new ScheduledThreadPoolExecutor(1); - mTimer.scheduleWithFixedDelay(new Runnable() { - @Override public void run() { - mInfoThread = (M3U8InfoThread) createLiveInfoThread(); - mInfoPool.execute(mInfoThread); - } - }, 0, mM3U8Option.getLiveUpdateInterval(), TimeUnit.MILLISECONDS); - getLoader().start(); - } - - private void closeTimer() { - if (mTimer != null && !mTimer.isShutdown()) { - mTimer.shutdown(); - } - } - - @Override protected void fail(BaseException e, boolean needRetry) { - super.fail(e, needRetry); - handleComplete(); - } - - @Override public M3U8LiveLoader getLoader() { - return (M3U8LiveLoader) super.getLoader(); + @Override public LoaderStructure BuildLoaderStructure() { + LoaderStructure structure = new LoaderStructure(); + structure.addComponent(new M3U8RecordHandler(getTaskWrapper())) + .addComponent(new M3U8InfoTask(getTaskWrapper())) + .addComponent(new LiveStateManager(getTaskWrapper(), getListener())); + structure.accept(getLoader()); + return structure; } } diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/vod/M3U8VodLoader.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/vod/M3U8VodLoader.java index 49024b45..23e0de7b 100644 --- a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/vod/M3U8VodLoader.java +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/vod/M3U8VodLoader.java @@ -15,35 +15,36 @@ */ package com.arialyy.aria.m3u8.vod; -import android.os.Bundle; import android.os.Handler; import android.os.Looper; -import android.os.Message; +import android.text.TextUtils; import android.util.SparseArray; -import com.arialyy.aria.core.TaskRecord; import com.arialyy.aria.core.ThreadRecord; +import com.arialyy.aria.core.common.AbsEntity; +import com.arialyy.aria.core.common.CompleteInfo; import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.event.Event; import com.arialyy.aria.core.event.EventMsgUtil; import com.arialyy.aria.core.event.PeerIndexEvent; -import com.arialyy.aria.core.inf.IThreadState; -import com.arialyy.aria.core.listener.IEventListener; -import com.arialyy.aria.core.listener.ISchedulers; +import com.arialyy.aria.core.inf.IThreadStateManager; +import com.arialyy.aria.core.loader.IInfoTask; +import com.arialyy.aria.core.loader.IRecordHandler; +import com.arialyy.aria.core.loader.IThreadTaskBuilder; import com.arialyy.aria.core.manager.ThreadTaskManager; -import com.arialyy.aria.core.processor.ITsMergeHandler; +import com.arialyy.aria.core.processor.IVodTsUrlConverter; import com.arialyy.aria.core.task.ThreadTask; import com.arialyy.aria.exception.BaseException; -import com.arialyy.aria.exception.TaskException; +import com.arialyy.aria.exception.M3U8Exception; import com.arialyy.aria.m3u8.BaseM3U8Loader; import com.arialyy.aria.m3u8.M3U8Listener; import com.arialyy.aria.m3u8.M3U8TaskOption; import com.arialyy.aria.m3u8.M3U8ThreadTaskAdapter; import com.arialyy.aria.util.ALog; -import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.FileUtil; import java.io.File; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutorService; @@ -55,7 +56,7 @@ import java.util.concurrent.locks.ReentrantLock; /** * M3U8点播文件下载器 */ -public class M3U8VodLoader extends BaseM3U8Loader { +final class M3U8VodLoader extends BaseM3U8Loader { /** * 最大执行数 */ @@ -81,9 +82,10 @@ public class M3U8VodLoader extends BaseM3U8Loader { private ExecutorService mJumpThreadPool; private Thread jumpThread = null; private M3U8TaskOption mM3U8Option; + private Looper mLooper; - M3U8VodLoader(M3U8Listener listener, DTaskWrapper wrapper) { - super(listener, wrapper); + M3U8VodLoader(DTaskWrapper wrapper, M3U8Listener listener) { + super(wrapper, listener); mM3U8Option = (M3U8TaskOption) wrapper.getM3u8Option(); mFlagQueue = new ArrayBlockingQueue<>(mM3U8Option.getMaxTsQueueNum()); EXEC_MAX_NUM = mM3U8Option.getMaxTsQueueNum(); @@ -91,10 +93,37 @@ public class M3U8VodLoader extends BaseM3U8Loader { EventMsgUtil.getDefault().register(this); } - @Override protected IThreadState createStateManager(Looper looper) { - mManager = new VodStateManager(looper, mRecord, mListener); - mStateHandler = new Handler(looper, mManager); - return mManager; + @Override protected M3U8Listener getListener() { + return (M3U8Listener) super.getListener(); + } + + SparseArray getBeforePeer() { + return mBeforePeer; + } + + int getCompleteNum() { + return mCompleteNum; + } + + void setCompleteNum(int mCompleteNum) { + this.mCompleteNum = mCompleteNum; + } + + int getCurrentFlagSize() { + mCurrentFlagSize = mFlagQueue.size(); + return mCurrentFlagSize; + } + + void setCurrentFlagSize(int currentFlagSize) { + mCurrentFlagSize = currentFlagSize; + } + + boolean isJump() { + return isJump; + } + + File getTempFile() { + return mTempFile; } @Override public void onDestroy() { @@ -115,7 +144,15 @@ public class M3U8VodLoader extends BaseM3U8Loader { return super.isBreak() || isDestroy; } - @Override protected void handleTask() { + @Override protected void handleTask(Looper looper) { + if (isBreak()) { + return; + } + mLooper = looper; + mInfoTask.run(); + } + + private void startThreadTask() { Thread th = new Thread(new Runnable() { @Override public void run() { while (!isBreak()) { @@ -193,7 +230,7 @@ public class M3U8VodLoader extends BaseM3U8Loader { */ private void addTaskToQueue(ThreadRecord tr) throws InterruptedException { ThreadTask task = createThreadTask(mCacheDir, tr, tr.threadId); - getTaskList().put(tr.threadId, task); + getTaskList().add(task); getEntity().getM3U8Entity().setPeerIndex(tr.threadId); TempFlag flag = startThreadTask(task, tr.threadId); if (flag != null) { @@ -222,10 +259,10 @@ public class M3U8VodLoader extends BaseM3U8Loader { } mManager.updateStateCount(); if (mCompleteNum <= 0) { - mListener.onStart(0); + getListener().onStart(0); } else { int percent = mCompleteNum * 100 / mRecord.threadRecords.size(); - mListener.onResume(percent); + getListener().onResume(percent); } } @@ -344,7 +381,7 @@ public class M3U8VodLoader extends BaseM3U8Loader { /** * 从指定位置恢复任务 */ - private synchronized void resumeTask() { + synchronized void resumeTask() { if (isBreak()) { ALog.e(TAG, "任务已停止,恢复任务失败"); return; @@ -388,11 +425,7 @@ public class M3U8VodLoader extends BaseM3U8Loader { } } - private M3U8Listener getListener() { - return (M3U8Listener) mListener; - } - - private void notifyWaitLock(boolean isComplete) { + void notifyWaitLock(boolean isComplete) { try { LOCK.lock(); if (isComplete) { @@ -449,236 +482,87 @@ public class M3U8VodLoader extends BaseM3U8Loader { return threadTask; } - /** - * M3U8线程状态管理 - */ - private class VodStateManager implements IThreadState { - private final String TAG = CommonUtil.getClassName(VodStateManager.class); - - /** - * 任务状态回调 - */ - private IEventListener listener; - private int startThreadNum; // 启动的线程总数 - private int cancelNum = 0; // 已经取消的线程的数 - private int stopNum = 0; // 已经停止的线程数 - private int failNum = 0; // 失败的线程数 - private long percent; //当前总进度,百分比进度 - private long progress; - private TaskRecord taskRecord; // 任务记录 - private Looper looper; - - /** - * @param taskRecord 任务记录 - * @param listener 任务事件 - */ - VodStateManager(Looper looper, TaskRecord taskRecord, IEventListener listener) { - this.looper = looper; - this.taskRecord = taskRecord; - for (ThreadRecord record : taskRecord.threadRecords) { - if (!record.isComplete) { - startThreadNum++; - } - } - this.listener = listener; - progress = getEntity().getCurrentProgress(); - } - - private void updateStateCount() { - cancelNum = 0; - stopNum = 0; - failNum = 0; - } - - /** - * 退出looper循环 - */ - private void quitLooper() { - ALog.d(TAG, "quitLooper"); - looper.quit(); - } - - @Override public boolean handleMessage(Message msg) { - int peerIndex = msg.getData().getInt(ISchedulers.DATA_M3U8_PEER_INDEX); - switch (msg.what) { - case STATE_STOP: - stopNum++; - removeSignThread((ThreadTask) msg.obj); - // 处理跳转位置后,恢复任务 - if (isJump && (stopNum == mCurrentFlagSize || mCurrentFlagSize == 0) && !isBreak()) { - resumeTask(); - return true; - } - - if (isBreak()) { - ALog.d(TAG, String.format("vod任务【%s】停止", mTempFile.getName())); - quitLooper(); - } - break; - case STATE_CANCEL: - cancelNum++; - removeSignThread((ThreadTask) msg.obj); - - if (isBreak()) { - ALog.d(TAG, String.format("vod任务【%s】取消", mTempFile.getName())); - quitLooper(); - } - break; - case STATE_FAIL: - failNum++; - for (ThreadRecord tr : mRecord.threadRecords) { - if (tr.threadId == peerIndex) { - mBeforePeer.put(peerIndex, tr); - break; - } - } - - getListener().onPeerFail(mTaskWrapper.getKey(), - msg.getData().getString(ISchedulers.DATA_M3U8_PEER_PATH), peerIndex); - if (isFail()) { - ALog.d(TAG, String.format("vod任务【%s】失败", mTempFile.getName())); - Bundle b = msg.getData(); - listener.onFail(b.getBoolean(KEY_RETRY, true), - (BaseException) b.getSerializable(KEY_ERROR_INFO)); - quitLooper(); - } - break; - case STATE_COMPLETE: - if (isBreak()) { - quitLooper(); - } - mCompleteNum++; - // 正在切换位置时,切片完成,队列减小 - if (isJump) { - mCurrentFlagSize--; - if (mCurrentFlagSize < 0) { - mCurrentFlagSize = 0; - } - } + @Override public void addComponent(IRecordHandler recordHandler) { + mRecordHandler = recordHandler; + mRecord = mRecordHandler.getRecord(0); + } - removeSignThread((ThreadTask) msg.obj); - getListener().onPeerComplete(mTaskWrapper.getKey(), - msg.getData().getString(ISchedulers.DATA_M3U8_PEER_PATH), peerIndex); - handlerPercent(); - if (!isJump) { - notifyWaitLock(true); + @Override public void addComponent(IInfoTask infoTask) { + mInfoTask = infoTask; + final List urls = new ArrayList<>(); + mInfoTask.setCallback(new IInfoTask.Callback() { + @Override public void onSucceed(String key, CompleteInfo info) { + IVodTsUrlConverter converter = mM3U8Option.getVodUrlConverter(); + if (converter != null) { + if (TextUtils.isEmpty(mM3U8Option.getBandWidthUrl())) { + urls.addAll( + converter.convert(getEntity().getUrl(), (List) info.obj)); + } else { + urls.addAll( + converter.convert(mM3U8Option.getBandWidthUrl(), (List) info.obj)); } - if (isComplete()) { - ALog.d(TAG, String.format( - "startThreadNum = %s, stopNum = %s, cancelNum = %s, failNum = %s, completeNum = %s, flagQueueSize = %s", - startThreadNum, stopNum, cancelNum, failNum, mCompleteNum, mFlagQueue.size())); - ALog.d(TAG, String.format("vod任务【%s】完成", mTempFile.getName())); - - if (mM3U8Option.isGenerateIndexFile()) { - if (generateIndexFile(false)) { - listener.onComplete(); - } else { - listener.onFail(false, new TaskException(TAG, "创建索引文件失败")); - } - } else if (mM3U8Option.isMergeFile()) { - if (mergeFile()) { - listener.onComplete(); - } else { - listener.onFail(false, null); - } - } else { - listener.onComplete(); - } - quitLooper(); - } - break; - case STATE_RUNNING: - progress += (long) msg.obj; - break; + } else { + urls.addAll((Collection) info.obj); + } + if (urls.isEmpty()) { + fail(new M3U8Exception(TAG, "获取地址失败"), false); + return; + } else if (!urls.get(0).startsWith("http")) { + fail(new M3U8Exception(TAG, "地址错误,请使用IVodTsUrlConverter处理你的url信息"), false); + return; + } + mM3U8Option.setUrls(urls); + + if (isStop) { + getListener().onStop(getEntity().getCurrentProgress()); + } else if (isCancel) { + getListener().onCancel(); + } else { + startThreadTask(); + } } - return true; - } - private void removeSignThread(ThreadTask threadTask) { - int index = getTaskList().indexOfValue(threadTask); - if (index != -1) { - getTaskList().removeAt(index); + @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { + fail(e, needRetry); } - ThreadTaskManager.getInstance().removeSingleTaskThread(mTaskWrapper.getKey(), threadTask); - } + }); + } - /** - * 设置进度 - */ - private void handlerPercent() { - int completeNum = mM3U8Option.getCompleteNum(); - completeNum++; - mM3U8Option.setCompleteNum(completeNum); - int percent = completeNum * 100 / taskRecord.threadRecords.size(); - getEntity().setPercent(percent); - getEntity().update(); - this.percent = percent; + protected void fail(BaseException e, boolean needRetry) { + if (isBreak()) { + return; } + getListener().onFail(needRetry, e); + onDestroy(); + } - @Override public boolean isFail() { - printInfo("isFail"); - return failNum != 0 && failNum == mFlagQueue.size() && !isJump; - } + /** + * 需要在 {@link #addComponent(IRecordHandler)}后调用 + */ + @Override public void addComponent(IThreadStateManager threadState) { + mManager = (VodStateManager) threadState; + mStateHandler = new Handler(mLooper, mManager.getHandlerCallback()); + mManager.setVodLoader(this); + mManager.setLooper(mRecord, mLooper); + } - @Override public boolean isComplete() { - if (mM3U8Option.isIgnoreFailureTs()) { - return mCompleteNum + failNum >= taskRecord.threadRecords.size() && !isJump; - } else { - return mCompleteNum == taskRecord.threadRecords.size() && !isJump; - } - } + /** + * m3u8 不需要实现这个 + */ + @Deprecated + @Override public void addComponent(IThreadTaskBuilder builder) { - @Override public long getCurrentProgress() { - return progress; - } + } - private void printInfo(String tag) { - if (false) { - ALog.d(tag, String.format( - "startThreadNum = %s, stopNum = %s, cancelNum = %s, failNum = %s, completeNum = %s, flagQueueSize = %s", - startThreadNum, stopNum, cancelNum, failNum, mCompleteNum, mFlagQueue.size())); - } + @Override protected void checkComponent() { + if (mRecordHandler == null) { + throw new NullPointerException("任务记录组件为空"); } - - /** - * 合并文件 - * - * @return {@code true} 合并成功,{@code false}合并失败 - */ - private boolean mergeFile() { - ITsMergeHandler mergeHandler = mM3U8Option.getMergeHandler(); - String cacheDir = getCacheDir(); - List partPath = new ArrayList<>(); - for (ThreadRecord tr : taskRecord.threadRecords) { - partPath.add(BaseM3U8Loader.getTsFilePath(cacheDir, tr.threadId)); - } - boolean isSuccess; - if (mergeHandler != null) { - isSuccess = mergeHandler.merge(getEntity().getM3U8Entity(), partPath); - - if (mergeHandler.getClass().isAnonymousClass()) { - mM3U8Option.setMergeHandler(null); - } - } else { - isSuccess = FileUtil.mergeFile(taskRecord.filePath, partPath); - } - if (isSuccess) { - // 合并成功,删除缓存文件 - File[] files = new File(cacheDir).listFiles(); - for (File f : files) { - if (f.exists()) { - f.delete(); - } - } - File cDir = new File(cacheDir); - if (cDir.exists()) { - cDir.delete(); - } - return true; - } else { - ALog.e(TAG, "合并失败"); - return false; - } + if (mInfoTask == null) { + throw new NullPointerException(("文件信息组件为空")); + } + if (mManager == null) { + throw new NullPointerException("任务状态管理组件为空"); } } diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/vod/M3U8VodUtil.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/vod/M3U8VodUtil.java index 46f82d51..86b97bd6 100644 --- a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/vod/M3U8VodUtil.java +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/vod/M3U8VodUtil.java @@ -15,25 +15,17 @@ */ package com.arialyy.aria.m3u8.vod; -import android.text.TextUtils; -import com.arialyy.aria.core.common.AbsEntity; -import com.arialyy.aria.core.common.CompleteInfo; import com.arialyy.aria.core.download.DTaskWrapper; -import com.arialyy.aria.core.inf.OnFileInfoCallback; import com.arialyy.aria.core.listener.IEventListener; -import com.arialyy.aria.core.loader.AbsLoader; +import com.arialyy.aria.core.loader.AbsNormalLoader; import com.arialyy.aria.core.loader.AbsNormalLoaderUtil; -import com.arialyy.aria.core.processor.IVodTsUrlConverter; +import com.arialyy.aria.core.loader.LoaderStructure; import com.arialyy.aria.core.wrapper.AbsTaskWrapper; -import com.arialyy.aria.exception.BaseException; -import com.arialyy.aria.exception.M3U8Exception; import com.arialyy.aria.http.HttpTaskOption; -import com.arialyy.aria.m3u8.M3U8InfoThread; +import com.arialyy.aria.m3u8.M3U8InfoTask; import com.arialyy.aria.m3u8.M3U8Listener; +import com.arialyy.aria.m3u8.M3U8RecordHandler; import com.arialyy.aria.m3u8.M3U8TaskOption; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; /** * M3U8点播文件下载工具 @@ -43,10 +35,7 @@ import java.util.List; * 3、完成所有分片下载后,合并ts文件 * 4、删除该隐藏文件夹 */ -public class M3U8VodUtil extends AbsNormalLoaderUtil { - - private List mUrls = new ArrayList<>(); - private M3U8TaskOption mM3U8Option; +public final class M3U8VodUtil extends AbsNormalLoaderUtil { public M3U8VodUtil(AbsTaskWrapper wrapper, IEventListener listener) { super(wrapper, listener); @@ -56,48 +45,19 @@ public class M3U8VodUtil extends AbsNormalLoaderUtil { return (DTaskWrapper) super.getTaskWrapper(); } - @Override protected AbsLoader createLoader() { + @Override public AbsNormalLoader getLoader() { getTaskWrapper().generateM3u8Option(M3U8TaskOption.class); getTaskWrapper().generateTaskOption(HttpTaskOption.class); - mM3U8Option = (M3U8TaskOption) getTaskWrapper().getM3u8Option(); - return new M3U8VodLoader((M3U8Listener) getListener(), getTaskWrapper()); + return mLoader == null ? new M3U8VodLoader(getTaskWrapper(), (M3U8Listener) getListener()) + : mLoader; } - @Override protected Runnable createInfoThread() { - return new M3U8InfoThread(getTaskWrapper(), new OnFileInfoCallback() { - @Override public void onComplete(String key, CompleteInfo info) { - IVodTsUrlConverter converter = mM3U8Option.getVodUrlConverter(); - if (converter != null) { - if (TextUtils.isEmpty(mM3U8Option.getBandWidthUrl())) { - mUrls.addAll( - converter.convert(getTaskWrapper().getEntity().getUrl(), (List) info.obj)); - } else { - mUrls.addAll( - converter.convert(mM3U8Option.getBandWidthUrl(), (List) info.obj)); - } - } else { - mUrls.addAll((Collection) info.obj); - } - if (mUrls.isEmpty()) { - fail(new M3U8Exception(TAG, "获取地址失败"), false); - return; - } else if (!mUrls.get(0).startsWith("http")) { - fail(new M3U8Exception(TAG, "地址错误,请使用IVodTsUrlConverter处理你的url信息"), false); - return; - } - mM3U8Option.setUrls(mUrls); - if (isStop()) { - getListener().onStop(getTaskWrapper().getEntity().getCurrentProgress()); - } else if (isCancel()) { - getListener().onCancel(); - } else { - getLoader().start(); - } - } - - @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { - fail(e, needRetry); - } - }); + @Override public LoaderStructure BuildLoaderStructure() { + LoaderStructure structure = new LoaderStructure(); + structure.addComponent(new M3U8RecordHandler(getTaskWrapper())) + .addComponent(new M3U8InfoTask(getTaskWrapper())) + .addComponent(new VodStateManager(getTaskWrapper(), (M3U8Listener) getListener())); + structure.accept(getLoader()); + return structure; } } diff --git a/M3U8Component/src/main/java/com/arialyy/aria/m3u8/vod/VodStateManager.java b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/vod/VodStateManager.java new file mode 100644 index 00000000..ff1b7dbf --- /dev/null +++ b/M3U8Component/src/main/java/com/arialyy/aria/m3u8/vod/VodStateManager.java @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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.arialyy.aria.m3u8.vod; + +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import com.arialyy.aria.core.TaskRecord; +import com.arialyy.aria.core.ThreadRecord; +import com.arialyy.aria.core.download.DTaskWrapper; +import com.arialyy.aria.core.download.DownloadEntity; +import com.arialyy.aria.core.inf.IThreadStateManager; +import com.arialyy.aria.core.listener.ISchedulers; +import com.arialyy.aria.core.loader.ILoaderVisitor; +import com.arialyy.aria.core.manager.ThreadTaskManager; +import com.arialyy.aria.core.processor.ITsMergeHandler; +import com.arialyy.aria.core.task.ThreadTask; +import com.arialyy.aria.exception.BaseException; +import com.arialyy.aria.exception.TaskException; +import com.arialyy.aria.m3u8.BaseM3U8Loader; +import com.arialyy.aria.m3u8.M3U8Listener; +import com.arialyy.aria.m3u8.M3U8TaskOption; +import com.arialyy.aria.util.ALog; +import com.arialyy.aria.util.CommonUtil; +import com.arialyy.aria.util.FileUtil; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * m3u8 点播下载状态管理器 + */ +public final class VodStateManager implements IThreadStateManager { + private final String TAG = CommonUtil.getClassName(getClass()); + + private M3U8Listener listener; + private int startThreadNum; // 启动的线程总数 + private int cancelNum = 0; // 已经取消的线程的数 + private int stopNum = 0; // 已经停止的线程数 + private int failNum = 0; // 失败的线程数 + private long percent; //当前总进度,百分比进度 + private long progress; + private TaskRecord taskRecord; // 任务记录 + private Looper looper; + private DTaskWrapper wrapper; + private M3U8TaskOption m3U8Option; + private M3U8VodLoader loader; + + /** + * @param listener 任务事件 + */ + VodStateManager(DTaskWrapper wrapper, M3U8Listener listener) { + this.wrapper = wrapper; + this.listener = listener; + m3U8Option = (M3U8TaskOption) wrapper.getM3u8Option(); + progress = wrapper.getEntity().getCurrentProgress(); + } + + private Handler.Callback callback = new Handler.Callback() { + @Override public boolean handleMessage(Message msg) { + int peerIndex = msg.getData().getInt(ISchedulers.DATA_M3U8_PEER_INDEX); + switch (msg.what) { + case STATE_STOP: + stopNum++; + removeSignThread((ThreadTask) msg.obj); + // 处理跳转位置后,恢复任务 + if (loader.isJump() + && (stopNum == loader.getCurrentFlagSize() || loader.getCurrentFlagSize() == 0) + && !loader.isBreak()) { + loader.resumeTask(); + return true; + } + + if (loader.isBreak()) { + ALog.d(TAG, String.format("vod任务【%s】停止", loader.getTempFile().getName())); + quitLooper(); + } + break; + case STATE_CANCEL: + cancelNum++; + removeSignThread((ThreadTask) msg.obj); + + if (loader.isBreak()) { + ALog.d(TAG, String.format("vod任务【%s】取消", loader.getTempFile().getName())); + quitLooper(); + } + break; + case STATE_FAIL: + failNum++; + for (ThreadRecord tr : taskRecord.threadRecords) { + if (tr.threadId == peerIndex) { + loader.getBeforePeer().put(peerIndex, tr); + break; + } + } + + getListener().onPeerFail(wrapper.getKey(), + msg.getData().getString(ISchedulers.DATA_M3U8_PEER_PATH), peerIndex); + if (isFail()) { + ALog.d(TAG, String.format("vod任务【%s】失败", loader.getTempFile().getName())); + Bundle b = msg.getData(); + listener.onFail(b.getBoolean(KEY_RETRY, true), + (BaseException) b.getSerializable(KEY_ERROR_INFO)); + quitLooper(); + } + break; + case STATE_COMPLETE: + if (loader.isBreak()) { + quitLooper(); + } + loader.setCompleteNum(loader.getCompleteNum() + 1); + // 正在切换位置时,切片完成,队列减小 + if (loader.isJump()) { + loader.setCurrentFlagSize(loader.getCurrentFlagSize() - 1); + if (loader.getCurrentFlagSize() < 0) { + loader.setCurrentFlagSize(0); + } + } + + removeSignThread((ThreadTask) msg.obj); + getListener().onPeerComplete(wrapper.getKey(), + msg.getData().getString(ISchedulers.DATA_M3U8_PEER_PATH), peerIndex); + handlerPercent(); + if (!loader.isJump()) { + loader.notifyWaitLock(true); + } + if (isComplete()) { + ALog.d(TAG, String.format( + "startThreadNum = %s, stopNum = %s, cancelNum = %s, failNum = %s, completeNum = %s, flagQueueSize = %s", + startThreadNum, stopNum, cancelNum, failNum, loader.getCompleteNum(), + loader.getCurrentFlagSize())); + ALog.d(TAG, String.format("vod任务【%s】完成", loader.getTempFile().getName())); + + if (m3U8Option.isGenerateIndexFile()) { + if (loader.generateIndexFile(false)) { + listener.onComplete(); + } else { + listener.onFail(false, new TaskException(TAG, "创建索引文件失败")); + } + } else if (m3U8Option.isMergeFile()) { + if (mergeFile()) { + listener.onComplete(); + } else { + listener.onFail(false, null); + } + } else { + listener.onComplete(); + } + quitLooper(); + } + break; + case STATE_RUNNING: + progress += (long) msg.obj; + break; + } + return true; + } + }; + + void updateStateCount() { + cancelNum = 0; + stopNum = 0; + failNum = 0; + } + + @Override public void setLooper(TaskRecord taskRecord, Looper looper) { + this.looper = looper; + this.taskRecord = taskRecord; + for (ThreadRecord record : taskRecord.threadRecords) { + if (!record.isComplete) { + startThreadNum++; + } + } + } + + @Override public Handler.Callback getHandlerCallback() { + return callback; + } + + private DownloadEntity getEntity() { + return wrapper.getEntity(); + } + + private M3U8Listener getListener() { + return listener; + } + + void setVodLoader(M3U8VodLoader loader) { + this.loader = loader; + } + + /** + * 退出looper循环 + */ + private void quitLooper() { + ALog.d(TAG, "quitLooper"); + looper.quit(); + } + + private void removeSignThread(ThreadTask threadTask) { + loader.getTaskList().remove(threadTask); + ThreadTaskManager.getInstance().removeSingleTaskThread(wrapper.getKey(), threadTask); + } + + /** + * 设置进度 + */ + private void handlerPercent() { + int completeNum = m3U8Option.getCompleteNum(); + completeNum++; + m3U8Option.setCompleteNum(completeNum); + int percent = completeNum * 100 / taskRecord.threadRecords.size(); + getEntity().setPercent(percent); + getEntity().update(); + this.percent = percent; + } + + @Override public boolean isFail() { + printInfo("isFail"); + return failNum != 0 && failNum == loader.getCurrentFlagSize() && !loader.isJump(); + } + + @Override public boolean isComplete() { + if (m3U8Option.isIgnoreFailureTs()) { + return loader.getCompleteNum() + failNum >= taskRecord.threadRecords.size() + && !loader.isJump(); + } else { + return loader.getCompleteNum() == taskRecord.threadRecords.size() && !loader.isJump(); + } + } + + @Override public long getCurrentProgress() { + return progress; + } + + private void printInfo(String tag) { + if (false) { + ALog.d(tag, String.format( + "startThreadNum = %s, stopNum = %s, cancelNum = %s, failNum = %s, completeNum = %s, flagQueueSize = %s", + startThreadNum, stopNum, cancelNum, failNum, loader.getCompleteNum(), + loader.getCurrentFlagSize())); + } + } + + /** + * 合并文件 + * + * @return {@code true} 合并成功,{@code false}合并失败 + */ + private boolean mergeFile() { + ITsMergeHandler mergeHandler = m3U8Option.getMergeHandler(); + String cacheDir = loader.getCacheDir(); + List partPath = new ArrayList<>(); + for (ThreadRecord tr : taskRecord.threadRecords) { + partPath.add(BaseM3U8Loader.getTsFilePath(cacheDir, tr.threadId)); + } + boolean isSuccess; + if (mergeHandler != null) { + isSuccess = mergeHandler.merge(getEntity().getM3U8Entity(), partPath); + + if (mergeHandler.getClass().isAnonymousClass()) { + m3U8Option.setMergeHandler(null); + } + } else { + isSuccess = FileUtil.mergeFile(taskRecord.filePath, partPath); + } + if (isSuccess) { + // 合并成功,删除缓存文件 + File[] files = new File(cacheDir).listFiles(); + for (File f : files) { + if (f.exists()) { + f.delete(); + } + } + File cDir = new File(cacheDir); + if (cDir.exists()) { + cDir.delete(); + } + return true; + } else { + ALog.e(TAG, "合并失败"); + return false; + } + } + + @Override public void accept(ILoaderVisitor visitor) { + visitor.addComponent(this); + } +} diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/common/RecordHandler.java b/PublicComponent/src/main/java/com/arialyy/aria/core/common/RecordHandler.java index 7f8eac62..cf8bdbd5 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/common/RecordHandler.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/common/RecordHandler.java @@ -45,6 +45,8 @@ public abstract class RecordHandler implements IRecordHandler { private TaskRecord mTaskRecord; private AbsTaskWrapper mTaskWrapper; private AbsNormalEntity mEntity; + protected String mFilePath; + protected long mFileSize; public RecordHandler(AbsTaskWrapper wrapper) { mTaskWrapper = wrapper; @@ -72,7 +74,8 @@ public abstract class RecordHandler implements IRecordHandler { * @return 任务记录 */ @Override - public TaskRecord getRecord() { + public TaskRecord getRecord(long fileSize) { + mFileSize = fileSize; mConfigFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName())); if (mConfigFile.exists()) { convertDb(); @@ -80,22 +83,7 @@ public abstract class RecordHandler implements IRecordHandler { onPre(); mTaskRecord = DbDataHelper.getTaskRecord(getFilePath(), mEntity.getTaskType()); if (mTaskRecord == null) { - if (!new File(getFilePath()).exists()) { - FileUtil.createFile(getFilePath()); - } initRecord(true); - } else { - File file = new File(mTaskRecord.filePath); - if (!file.exists()) { - ALog.w(TAG, String.format("文件【%s】不存在,重新分配线程区间", mTaskRecord.filePath)); - DbEntity.deleteData(ThreadRecord.class, "taskKey=?", mTaskRecord.filePath); - mTaskRecord.threadRecords.clear(); - mTaskRecord.threadNum = initTaskThreadNum(); - initRecord(false); - } else if (mTaskRecord.threadRecords == null || mTaskRecord.threadRecords.isEmpty()) { - mTaskRecord.threadNum = initTaskThreadNum(); - initRecord(false); - } } handlerTaskRecord(mTaskRecord); } @@ -172,7 +160,7 @@ public abstract class RecordHandler implements IRecordHandler { if (requestType == ITaskWrapper.M3U8_LIVE) { return; } - long blockSize = mEntity.getFileSize() / mTaskRecord.threadNum; + long blockSize = getFileSize() / mTaskRecord.threadNum; // 处理线程区间记录 for (int i = 0; i < mTaskRecord.threadNum; i++) { long startL = i * blockSize, endL = (i + 1) * blockSize; @@ -193,6 +181,10 @@ public abstract class RecordHandler implements IRecordHandler { ALog.d(TAG, String.format("保存记录,线程记录数:%s", mTaskRecord.threadRecords.size())); } + protected long getFileSize() { + return mFileSize; + } + /** * 获取任务路径 * diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/common/RecordHelper.java b/PublicComponent/src/main/java/com/arialyy/aria/core/common/RecordHelper.java index 9b1ee2ef..99de4cc3 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/common/RecordHelper.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/common/RecordHelper.java @@ -149,28 +149,29 @@ public class RecordHelper { * 处理单线程的任务的记录 */ public void handleSingleThreadRecord() { - File file = new File(mTaskRecord.filePath); + // mTaskRecord.isBlock是为了兼容以前的文件格式 + File file = new File( + mTaskRecord.isBlock ? String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, 0) + : mTaskRecord.filePath); ThreadRecord tr = mTaskRecord.threadRecords.get(0); if (!file.exists()) { ALog.w(TAG, String.format("文件【%s】不存在,任务将重新开始", file.getPath())); tr.startLocation = 0; tr.isComplete = false; tr.endLocation = mWrapper.getEntity().getFileSize(); - } else if (mTaskRecord.isBlock) { - if (file.length() > mWrapper.getEntity().getFileSize()) { - ALog.i(TAG, String.format("文件【%s】错误,任务重新开始", file.getPath())); - FileUtil.deleteFile(file); - tr.startLocation = 0; + } else if (file.length() > mWrapper.getEntity().getFileSize()) { + ALog.i(TAG, String.format("文件【%s】错误,任务重新开始", file.getPath())); + FileUtil.deleteFile(file); + tr.startLocation = 0; + tr.isComplete = false; + tr.endLocation = mWrapper.getEntity().getFileSize(); + } else if (file.length() == mWrapper.getEntity().getFileSize()) { + tr.isComplete = true; + } else { + if (file.length() != tr.startLocation) { + ALog.i(TAG, String.format("修正【%s】的进度记录为:%s", file.getPath(), file.length())); + tr.startLocation = file.length(); tr.isComplete = false; - tr.endLocation = mWrapper.getEntity().getFileSize(); - } else if (file.length() == mWrapper.getEntity().getFileSize()) { - tr.isComplete = true; - } else { - if (file.length() != tr.startLocation) { - ALog.i(TAG, String.format("修正【%s】的进度记录为:%s", file.getPath(), file.length())); - tr.startLocation = file.length(); - tr.isComplete = false; - } } } mWrapper.setNewTask(false); diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/group/AbsGroupLoader.java b/PublicComponent/src/main/java/com/arialyy/aria/core/group/AbsGroupLoader.java new file mode 100644 index 00000000..bab6fab0 --- /dev/null +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/group/AbsGroupLoader.java @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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.arialyy.aria.core.group; + +import android.os.Handler; +import android.os.Looper; +import com.arialyy.aria.core.config.Configuration; +import com.arialyy.aria.core.download.DGTaskWrapper; +import com.arialyy.aria.core.download.DTaskWrapper; +import com.arialyy.aria.core.inf.IEntity; +import com.arialyy.aria.core.inf.IThreadStateManager; +import com.arialyy.aria.core.listener.IDGroupListener; +import com.arialyy.aria.core.listener.IEventListener; +import com.arialyy.aria.core.loader.IInfoTask; +import com.arialyy.aria.core.loader.ILoader; +import com.arialyy.aria.core.loader.ILoaderVisitor; +import com.arialyy.aria.core.loader.IRecordHandler; +import com.arialyy.aria.core.loader.IThreadTaskBuilder; +import com.arialyy.aria.core.wrapper.AbsTaskWrapper; +import com.arialyy.aria.util.ALog; +import com.arialyy.aria.util.CommonUtil; +import java.io.File; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * 组合任务加载器 + */ +public abstract class AbsGroupLoader implements ILoaderVisitor, ILoader { + protected final String TAG = CommonUtil.getClassName(getClass()); + + private long mCurrentLocation = 0; + protected IDGroupListener mListener; + private ScheduledThreadPoolExecutor mTimer; + private long mUpdateInterval; + private boolean isStop = false, isCancel = false; + private Handler mScheduler; + private SimpleSubQueue mSubQueue = SimpleSubQueue.newInstance(); + private Map mExeLoader = new WeakHashMap<>(); + private Map mCache = new WeakHashMap<>(); + private DGTaskWrapper mGTWrapper; + private GroupRunState mState; + + protected IInfoTask mInfoTask; + + protected AbsGroupLoader(AbsTaskWrapper groupWrapper, IEventListener listener) { + mListener = (IDGroupListener) listener; + mGTWrapper = (DGTaskWrapper) groupWrapper; + mUpdateInterval = Configuration.getInstance().downloadCfg.getUpdateInterval(); + } + + /** + * 处理任务 + */ + protected abstract void handlerTask(Looper looper); + + /** + * 创建子任务加载器工具 + * + * @param needGetFileInfo {@code true} 需要获取文件信息。{@code false} 不需要获取文件信息 + */ + protected abstract AbsSubDLoadUtil createSubLoader(DTaskWrapper wrapper, boolean needGetFileInfo); + + protected DGTaskWrapper getWrapper() { + return mGTWrapper; + } + + protected GroupRunState getState() { + return mState; + } + + public Handler getScheduler() { + return mScheduler; + } + + /** + * 初始化组合任务状态 + */ + private void initState(Looper looper) { + mState = new GroupRunState(getWrapper().getKey(), mListener, mSubQueue); + for (DTaskWrapper wrapper : mGTWrapper.getSubTaskWrapper()) { + File subFile = new File(wrapper.getEntity().getFilePath()); + if (wrapper.getEntity().getState() == IEntity.STATE_COMPLETE + && subFile.exists() + && subFile.length() == wrapper.getEntity().getFileSize()) { + mState.updateCompleteNum(); + mCurrentLocation += wrapper.getEntity().getFileSize(); + } else { + if (!subFile.exists()) { + wrapper.getEntity().setCurrentProgress(0); + } + wrapper.getEntity().setState(IEntity.STATE_POST_PRE); + mCache.put(wrapper.getKey(), wrapper); + mCurrentLocation += wrapper.getEntity().getCurrentProgress(); + } + } + if (getWrapper().getSubTaskWrapper().size() != mState.getCompleteNum()) { + getWrapper().setState(IEntity.STATE_POST_PRE); + } + mState.updateProgress(mCurrentLocation); + mScheduler = new Handler(looper, SimpleSchedulers.newInstance(mState)); + } + + @Override public String getKey() { + return mGTWrapper.getKey(); + } + + /** + * 启动子任务下载 + * + * @param url 子任务下载地址 + */ + void startSubTask(String url) { + if (!checkSubTask(url, "开始")) { + return; + } + if (!mState.isRunning) { + startTimer(); + } + AbsSubDLoadUtil d = getDownloader(url, false); + if (d != null && !d.isRunning()) { + mSubQueue.startTask(d); + } + } + + /** + * 停止子任务下载 + * + * @param url 子任务下载地址 + */ + void stopSubTask(String url) { + if (!checkSubTask(url, "停止")) { + return; + } + AbsSubDLoadUtil d = getDownloader(url, false); + if (d != null && d.isRunning()) { + mSubQueue.stopTask(d); + } + } + + /** + * 检查子任务 + * + * @param url 子任务url + * @param type 任务类型 + * @return {@code true} 任务可以下载 + */ + private boolean checkSubTask(String url, String type) { + DTaskWrapper wrapper = mCache.get(url); + if (wrapper != null) { + if (wrapper.getState() == IEntity.STATE_COMPLETE) { + ALog.w(TAG, "任务【" + url + "】已完成," + type + "失败"); + return false; + } + } else { + ALog.w(TAG, "任务组中没有该任务【" + url + "】," + type + "失败"); + return false; + } + return true; + } + + /** + * 通过地址获取下载器 + * + * @param url 子任务下载地址 + */ + private AbsSubDLoadUtil getDownloader(String url, boolean needGetFileInfo) { + AbsSubDLoadUtil d = mExeLoader.get(url); + if (d == null) { + return createSubLoader(mCache.get(url), needGetFileInfo); + } + return d; + } + + @Override public boolean isRunning() { + return mState != null && mState.isRunning; + } + + @Override public void cancel() { + isCancel = true; + closeTimer(); + onPreCancel(); + + mSubQueue.removeAllTask(); + mListener.onCancel(); + } + + /** + * onCancel前的操作 + */ + protected void onPreCancel() { + + } + + @Override public void stop() { + isStop = true; + closeTimer(); + if (onPreStop()) { + return; + } + mSubQueue.stopAllTask(); + } + + /** + * onStop前的操作 + * + * @return 返回{@code true},直接回调{@link IDGroupListener#onStop(long)} + */ + protected boolean onPreStop() { + + return false; + } + + @Override public void run() { + checkComponent(); + if (isStop || isCancel) { + closeTimer(); + return; + } + startRunningFlow(); + } + + /** + * 开始进度流程 + */ + private void startRunningFlow() { + closeTimer(); + Looper.prepare(); + Looper looper = Looper.myLooper(); + initState(looper); + getState().setSubSize(getWrapper().getSubTaskWrapper().size()); + if (getState().getCompleteNum() == getState().getSubSize()) { + mListener.onComplete(); + return; + } + + mListener.onPostPre(mGTWrapper.getEntity().getFileSize()); + if (mCurrentLocation > 0) { + mListener.onResume(mCurrentLocation); + } else { + mListener.onStart(mCurrentLocation); + } + startTimer(); + handlerTask(looper); + Looper.loop(); + } + + private synchronized void startTimer() { + mState.isRunning = true; + mTimer = new ScheduledThreadPoolExecutor(1); + mTimer.scheduleWithFixedDelay(new Runnable() { + @Override public void run() { + if (!mState.isRunning) { + closeTimer(); + } else if (mCurrentLocation >= 0) { + long t = 0; + for (DTaskWrapper te : mGTWrapper.getSubTaskWrapper()) { + if (te.getState() == IEntity.STATE_COMPLETE) { + t += te.getEntity().getFileSize(); + } else { + t += te.getEntity().getCurrentProgress(); + } + } + mCurrentLocation = t; + mState.updateProgress(mCurrentLocation); + mListener.onProgress(t); + } + } + }, 0, mUpdateInterval, TimeUnit.MILLISECONDS); + } + + /** + * 启动子任务下载器 + */ + protected void startSubLoader(AbsSubDLoadUtil loader) { + mExeLoader.put(loader.getKey(), loader); + mSubQueue.startTask(loader); + } + + @Override public boolean isBreak() { + if (isCancel || isStop) { + //ALog.d(TAG, "isCancel = " + isCancel + ", isStop = " + isStop); + ALog.d(TAG, String.format("任务【%s】已停止或取消了", mGTWrapper.getKey())); + return true; + } + return false; + } + + private synchronized void closeTimer() { + if (mTimer != null && !mTimer.isShutdown()) { + mTimer.shutdown(); + } + } + + @Override public long getCurrentProgress() { + return mCurrentLocation; + } + + /** + * @deprecated 组合任务不需要实现这个,记录交由其子任务处理 + */ + @Deprecated + @Override public void addComponent(IRecordHandler recordHandler) { + + } + + /** + * @deprecated 组合任务不需要实现这个,线程创建交有子任务处理 + */ + @Deprecated + @Override public void addComponent(IThreadTaskBuilder builder) { + + } + + /** + * @deprecated 组合任务不需要实现这个,其内部是一个子任务调度器,并不是线程状态管理器 + */ + @Deprecated + @Override public void addComponent(IThreadStateManager threadState) { + + } + + /** + * 检查组件: {@link #mInfoTask} + */ + private void checkComponent() { + if (mInfoTask == null) { + throw new NullPointerException(("文件信息组件为空")); + } + } +} diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/group/AbsGroupLoaderUtil.java b/PublicComponent/src/main/java/com/arialyy/aria/core/group/AbsGroupLoaderUtil.java index 1f0ba27e..520486e2 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/group/AbsGroupLoaderUtil.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/group/AbsGroupLoaderUtil.java @@ -15,284 +15,90 @@ */ package com.arialyy.aria.core.group; -import android.os.Handler; -import android.os.Looper; -import com.arialyy.aria.core.config.Configuration; -import com.arialyy.aria.core.download.DGTaskWrapper; -import com.arialyy.aria.core.download.DTaskWrapper; -import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IUtil; -import com.arialyy.aria.core.listener.IDGroupListener; import com.arialyy.aria.core.listener.IEventListener; +import com.arialyy.aria.core.loader.LoaderStructure; import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.CommonUtil; -import java.io.File; -import java.util.Map; -import java.util.WeakHashMap; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; /** * Created by AriaL on 2017/6/30. * 任务组核心逻辑 */ -public abstract class AbsGroupLoaderUtil implements IUtil, Runnable { - protected final String TAG = CommonUtil.getClassName(getClass()); +public abstract class AbsGroupLoaderUtil implements IUtil { - private long mCurrentLocation = 0; - protected IDGroupListener mListener; - private ScheduledThreadPoolExecutor mTimer; - private long mUpdateInterval; + protected String TAG = CommonUtil.getClassName(getClass()); + private IEventListener mListener; + protected AbsGroupLoader mLoader; + private AbsTaskWrapper mTaskWrapper; private boolean isStop = false, isCancel = false; - private Handler mScheduler; - private SimpleSubQueue mSubQueue = SimpleSubQueue.newInstance(); - private Map mExeLoader = new WeakHashMap<>(); - private Map mCache = new WeakHashMap<>(); - private DGTaskWrapper mGTWrapper; - private GroupRunState mState; - protected AbsGroupLoaderUtil(AbsTaskWrapper groupWrapper, IEventListener listener) { - mListener = (IDGroupListener) listener; - mGTWrapper = (DGTaskWrapper) groupWrapper; - mUpdateInterval = Configuration.getInstance().downloadCfg.getUpdateInterval(); - initState(); + protected AbsGroupLoaderUtil(AbsTaskWrapper wrapper, IEventListener listener) { + mTaskWrapper = wrapper; + mListener = listener; + mLoader = getLoader(); } - /** - * 创建子任务加载器工具 - * - * @param needGetFileInfo {@code true} 需要获取文件信息。{@code false} 不需要获取文件信息 - */ - protected abstract AbsSubDLoadUtil createSubLoader(DTaskWrapper wrapper, boolean needGetFileInfo); + protected abstract AbsGroupLoader getLoader(); - protected DGTaskWrapper getWrapper() { - return mGTWrapper; - } - - protected GroupRunState getState() { - return mState; - } + protected abstract LoaderStructure buildLoaderStructure(); - public Handler getScheduler() { - return mScheduler; + public IEventListener getListener() { + return mListener; } - /** - * 初始化组合任务状态 - */ - private void initState() { - mState = new GroupRunState(getWrapper().getKey(), mListener, mSubQueue); - for (DTaskWrapper wrapper : mGTWrapper.getSubTaskWrapper()) { - File subFile = new File(wrapper.getEntity().getFilePath()); - if (wrapper.getEntity().getState() == IEntity.STATE_COMPLETE - && subFile.exists() - && subFile.length() == wrapper.getEntity().getFileSize()) { - mState.updateCompleteNum(); - mCurrentLocation += wrapper.getEntity().getFileSize(); - } else { - if (!subFile.exists()) { - wrapper.getEntity().setCurrentProgress(0); - } - wrapper.getEntity().setState(IEntity.STATE_POST_PRE); - mCache.put(wrapper.getKey(), wrapper); - mCurrentLocation += wrapper.getEntity().getCurrentProgress(); - } - } - if (getWrapper().getSubTaskWrapper().size() != mState.getCompleteNum()) { - getWrapper().setState(IEntity.STATE_POST_PRE); - } - mState.updateProgress(mCurrentLocation); - mScheduler = new Handler(Looper.getMainLooper(), SimpleSchedulers.newInstance(mState)); + public AbsTaskWrapper getTaskWrapper() { + return mTaskWrapper; } @Override public String getKey() { - return mGTWrapper.getKey(); - } - - /** - * 启动子任务下载 - * - * @param url 子任务下载地址 - */ - public void startSubTask(String url) { - if (!checkSubTask(url, "开始")) return; - if (!mState.isRunning) { - startTimer(); - } - AbsSubDLoadUtil d = getDownloader(url); - if (d != null && !d.isRunning()) { - mSubQueue.startTask(d); - } - } - - /** - * 停止子任务下载 - * - * @param url 子任务下载地址 - */ - public void stopSubTask(String url) { - if (!checkSubTask(url, "停止")) return; - AbsSubDLoadUtil d = getDownloader(url); - if (d != null && d.isRunning()) { - mSubQueue.stopTask(d); - } - } - - /** - * 检查子任务 - * - * @param url 子任务url - * @param type 任务类型 - * @return {@code true} 任务可以下载 - */ - private boolean checkSubTask(String url, String type) { - DTaskWrapper wrapper = mCache.get(url); - if (wrapper != null) { - if (wrapper.getState() == IEntity.STATE_COMPLETE) { - ALog.w(TAG, "任务【" + url + "】已完成," + type + "失败"); - return false; - } - } else { - ALog.w(TAG, "任务组中没有该任务【" + url + "】," + type + "失败"); - return false; - } - return true; - } - - /** - * 通过地址获取下载器 - * - * @param url 子任务下载地址 - */ - private AbsSubDLoadUtil getDownloader(String url) { - AbsSubDLoadUtil d = mExeLoader.get(url); - if (d == null) { - return createSubLoader(mCache.get(url), true); - } - return d; + return mTaskWrapper.getKey(); } @Override public long getFileSize() { - return mGTWrapper.getEntity().getFileSize(); + return mTaskWrapper.getEntity().getFileSize(); } @Override public long getCurrentLocation() { - return mCurrentLocation; + return mLoader.getCurrentProgress(); } @Override public boolean isRunning() { - return mState.isRunning; + return mLoader.isRunning(); } - @Override public void cancel() { - isCancel = true; - closeTimer(); - onPreCancel(); + public void startSubTask(String url) { + getLoader().startSubTask(url); + } - mSubQueue.removeAllTask(); - mListener.onCancel(); + public void stopSubTask(String url) { + getLoader().stopSubTask(url); } /** - * onCancel前的操作 + * 取消下载 */ - public void onPreCancel() { - - } - - @Override public void stop() { - isStop = true; - closeTimer(); - if (onPreStop()) { - return; - } - mSubQueue.stopAllTask(); + @Override public void cancel() { + isCancel = true; + mLoader.cancel(); } /** - * onStop前的操作 - * - * @return 返回{@code true},直接回调{@link IDGroupListener#onStop(long)} + * 停止下载 */ - protected boolean onPreStop() { - - return false; + @Override public void stop() { + isStop = true; + mLoader.stop(); } @Override public void start() { - new Thread(this).start(); - } - - @Override public void run() { if (isStop || isCancel) { - closeTimer(); + ALog.w(TAG, "启动组合任务失败,任务已停止或已取消"); return; } - if (onStart()) { - startRunningFlow(); - } - } - /** - * 处理启动前的检查:获取组合任务大小 - * - * @return {@code false} 将不再走后续流程,任务介绍 - */ - protected boolean onStart() { - - return false; - } - - synchronized void closeTimer() { - if (mTimer != null && !mTimer.isShutdown()) { - mTimer.shutdown(); - } - } - - /** - * 开始进度流程 - */ - private void startRunningFlow() { - closeTimer(); - mListener.onPostPre(mGTWrapper.getEntity().getFileSize()); - if (mCurrentLocation > 0) { - mListener.onResume(mCurrentLocation); - } else { - mListener.onStart(mCurrentLocation); - } - startTimer(); - } - - private synchronized void startTimer() { - mState.isRunning = true; - mTimer = new ScheduledThreadPoolExecutor(1); - mTimer.scheduleWithFixedDelay(new Runnable() { - @Override public void run() { - if (!mState.isRunning) { - closeTimer(); - } else if (mCurrentLocation >= 0) { - long t = 0; - for (DTaskWrapper te : mGTWrapper.getSubTaskWrapper()) { - if (te.getState() == IEntity.STATE_COMPLETE) { - t += te.getEntity().getFileSize(); - } else { - t += te.getEntity().getCurrentProgress(); - } - } - mCurrentLocation = t; - mState.updateProgress(mCurrentLocation); - mListener.onProgress(t); - } - } - }, 0, mUpdateInterval, TimeUnit.MILLISECONDS); - } - - /** - * 启动子任务下载器 - */ - protected void startSubLoader(AbsSubDLoadUtil loader) { - mExeLoader.put(loader.getKey(), loader); - mSubQueue.startTask(loader); + buildLoaderStructure(); + new Thread(mLoader).start(); } } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/group/AbsSubDLoadUtil.java b/PublicComponent/src/main/java/com/arialyy/aria/core/group/AbsSubDLoadUtil.java index 359c554a..3fa50bb3 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/group/AbsSubDLoadUtil.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/group/AbsSubDLoadUtil.java @@ -20,37 +20,42 @@ import com.arialyy.aria.core.download.DTaskWrapper; import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.inf.IUtil; import com.arialyy.aria.core.listener.ISchedulers; -import com.arialyy.aria.core.loader.NormalLoader; +import com.arialyy.aria.core.loader.LoaderStructure; +import com.arialyy.aria.core.loader.SubLoader; +import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.CommonUtil; /** - * 子任务下载器,负责创建 + * 子任务下载器工具,需要在线程池中执行 */ -public abstract class AbsSubDLoadUtil implements IUtil { +public abstract class AbsSubDLoadUtil implements IUtil, Runnable { protected final String TAG = CommonUtil.getClassName(getClass()); - private NormalLoader mDLoader; + protected SubLoader mDLoader; private DTaskWrapper mWrapper; private Handler mSchedulers; private ChildDLoadListener mListener; private boolean needGetInfo; + private boolean isStop = false, isCancel = false; /** * @param schedulers 调度器 * @param needGetInfo {@code true} 需要获取文件信息。{@code false} 不需要获取文件信息 */ - protected AbsSubDLoadUtil(Handler schedulers, DTaskWrapper taskWrapper, boolean needGetInfo) { + protected AbsSubDLoadUtil(DTaskWrapper taskWrapper, Handler schedulers, boolean needGetInfo) { mWrapper = taskWrapper; mSchedulers = schedulers; this.needGetInfo = needGetInfo; mListener = new ChildDLoadListener(mSchedulers, AbsSubDLoadUtil.this); - mDLoader = createLoader(mListener, taskWrapper); + mDLoader = getLoader(); } /** * 创建加载器 */ - protected abstract NormalLoader createLoader(ChildDLoadListener listener, DTaskWrapper wrapper); + protected abstract SubLoader getLoader(); + + protected abstract LoaderStructure buildLoaderStructure(); protected boolean isNeedGetInfo() { return needGetInfo; @@ -72,6 +77,27 @@ public abstract class AbsSubDLoadUtil implements IUtil { return mWrapper.getEntity(); } + public ChildDLoadListener getListener() { + return mListener; + } + + @Override public void run() { + if (isStop || isCancel) { + return; + } + mListener.onPre(); + buildLoaderStructure(); + mDLoader.run(); + } + + /** + * 请在线程池中使用 + */ + @Deprecated + @Override public void start() { + throw new AssertionError("请在线程池中使用"); + } + /** * 重新开始任务 */ @@ -81,16 +107,24 @@ public abstract class AbsSubDLoadUtil implements IUtil { } } - public NormalLoader getDownloader() { + public SubLoader getDownloader() { return mDLoader; } + /** + * @deprecated 子任务不实现这个 + */ + @Deprecated @Override public long getFileSize() { - return mDLoader == null ? -1 : mDLoader.getFileSize(); + return -1; } + /** + * 子任务不实现这个 + */ + @Deprecated @Override public long getCurrentLocation() { - return mDLoader == null ? -1 : mDLoader.getCurrentLocation(); + return -1; } @Override public boolean isRunning() { @@ -98,6 +132,11 @@ public abstract class AbsSubDLoadUtil implements IUtil { } @Override public void cancel() { + if (isCancel) { + ALog.w(TAG, "子任务已取消"); + return; + } + isCancel = true; if (mDLoader != null && isRunning()) { mDLoader.cancel(); } else { @@ -106,6 +145,11 @@ public abstract class AbsSubDLoadUtil implements IUtil { } @Override public void stop() { + if (isStop) { + ALog.w(TAG, "任务已停止"); + return; + } + isStop = true; if (mDLoader != null && isRunning()) { mDLoader.stop(); } else { diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/group/ISubQueue.java b/PublicComponent/src/main/java/com/arialyy/aria/core/group/ISubQueue.java index 3019b935..70f80442 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/group/ISubQueue.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/group/ISubQueue.java @@ -15,14 +15,14 @@ */ package com.arialyy.aria.core.group; -import com.arialyy.aria.core.loader.AbsLoader; +import com.arialyy.aria.core.loader.AbsNormalLoader; import com.arialyy.aria.core.inf.IUtil; import com.arialyy.aria.core.config.DGroupConfig; /** * 组合任务子任务队列 * - * @param {@link AbsLoader}下载器 + * @param {@link AbsNormalLoader}下载器 */ interface ISubQueue { diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/group/SimpleSchedulers.java b/PublicComponent/src/main/java/com/arialyy/aria/core/group/SimpleSchedulers.java index 0f8beecb..945e5b87 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/group/SimpleSchedulers.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/group/SimpleSchedulers.java @@ -16,11 +16,12 @@ package com.arialyy.aria.core.group; +import android.os.Handler; import android.os.Message; import com.arialyy.aria.core.AriaConfig; import com.arialyy.aria.core.common.AbsEntity; import com.arialyy.aria.core.config.Configuration; -import com.arialyy.aria.core.listener.ISchedulers; +import com.arialyy.aria.core.inf.IThreadStateManager; import com.arialyy.aria.core.manager.ThreadTaskManager; import com.arialyy.aria.exception.TaskException; import com.arialyy.aria.util.ALog; @@ -32,7 +33,7 @@ import java.util.concurrent.TimeUnit; * 组合任务子任务调度器,用于调度任务的开始、停止、失败、完成等情况 * 该调度器生命周期和{@link AbsGroupLoaderUtil}生命周期一致 */ -class SimpleSchedulers implements ISchedulers { +class SimpleSchedulers implements Handler.Callback { private static final String TAG = "SimpleSchedulers"; private SimpleSubQueue mQueue; private GroupRunState mGState; @@ -48,9 +49,16 @@ class SimpleSchedulers implements ISchedulers { } @Override public boolean handleMessage(Message msg) { - AbsSubDLoadUtil loader = (AbsSubDLoadUtil) msg.obj; + // todo key 应该从bundle中获取 + String key = (String) msg.obj; + AbsSubDLoadUtil loader = mQueue.getLoaderUtil(key); + if (loader == null) { + ALog.e(TAG, "子任务loder不存在,key:" + key); + return true; + } + // todo 处理的是子任务的线程,需要删除 ThreadTaskManager.removeSingleTaskThread 删除线程任务 switch (msg.what) { - case RUNNING: + case IThreadStateManager.STATE_RUNNING: mGState.listener.onSubRunning(loader.getEntity()); break; case PRE: @@ -60,13 +68,13 @@ class SimpleSchedulers implements ISchedulers { case START: mGState.listener.onSubStart(loader.getEntity()); break; - case STOP: + case IThreadStateManager.STATE_STOP: handleStop(loader); break; - case COMPLETE: + case IThreadStateManager.STATE_COMPLETE: handleComplete(loader); break; - case FAIL: + case IThreadStateManager.STATE_FAIL: handleFail(loader); break; } @@ -128,9 +136,9 @@ class SimpleSchedulers implements ISchedulers { * 1、所有的子任务已经停止,则认为组合任务停止 * 2、completeNum + failNum + stopNum = subSize,则认为组合任务停止 */ - private synchronized void handleStop(AbsSubDLoadUtil loader) { - mGState.listener.onSubStop(loader.getEntity()); - mGState.countStopNum(loader.getKey()); + private synchronized void handleStop(AbsSubDLoadUtil loadUtil) { + mGState.listener.onSubStop(loadUtil.getEntity()); + mGState.countStopNum(loadUtil.getKey()); if (mGState.getStopNum() == mGState.getSubSize() || mGState.getStopNum() + mGState.getCompleteNum() diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/group/SimpleSubQueue.java b/PublicComponent/src/main/java/com/arialyy/aria/core/group/SimpleSubQueue.java index 65bec3af..3ca54e71 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/group/SimpleSubQueue.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/group/SimpleSubQueue.java @@ -61,6 +61,14 @@ class SimpleSubQueue implements ISubQueue { return mExec; } + AbsSubDLoadUtil getLoaderUtil(String key) { + AbsSubDLoadUtil sub = mExec.get(key); + if (sub != null) { + return sub; + } + return mCache.get(key); + } + /** * 获取缓存队列大小 */ @@ -81,7 +89,7 @@ class SimpleSubQueue implements ISubQueue { mCache.remove(fileer.getKey()); mExec.put(fileer.getKey(), fileer); ALog.d(TAG, String.format("开始执行子任务:%s", fileer.getEntity().getFileName())); - fileer.start(); + fileer.run(); } else { ALog.d(TAG, String.format("执行队列已满,任务进入缓存器中,key: %s", fileer.getKey())); addTask(fileer); diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/inf/IThreadState.java b/PublicComponent/src/main/java/com/arialyy/aria/core/inf/IThreadStateManager.java similarity index 93% rename from PublicComponent/src/main/java/com/arialyy/aria/core/inf/IThreadState.java rename to PublicComponent/src/main/java/com/arialyy/aria/core/inf/IThreadStateManager.java index f0af12ce..66c9f5fc 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/inf/IThreadState.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/inf/IThreadStateManager.java @@ -23,13 +23,15 @@ import com.arialyy.aria.core.loader.ILoaderComponent; /** * 线程任务状态 */ -public interface IThreadState extends ILoaderComponent { +public interface IThreadStateManager extends ILoaderComponent { int STATE_STOP = 0x01; int STATE_FAIL = 0x02; int STATE_CANCEL = 0x03; int STATE_COMPLETE = 0x04; int STATE_RUNNING = 0x05; int STATE_UPDATE_PROGRESS = 0x06; + int STATE_PRE = 0x07; + int STATE_START = 0x08; String KEY_RETRY = "KEY_RETRY"; String KEY_ERROR_INFO = "KEY_ERROR_INFO"; diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/AbsLoader.java b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/AbsNormalLoader.java similarity index 90% rename from PublicComponent/src/main/java/com/arialyy/aria/core/loader/AbsLoader.java rename to PublicComponent/src/main/java/com/arialyy/aria/core/loader/AbsNormalLoader.java index 28618e32..5e07406b 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/AbsLoader.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/AbsNormalLoader.java @@ -17,7 +17,7 @@ package com.arialyy.aria.core.loader; import android.os.Looper; import com.arialyy.aria.core.TaskRecord; -import com.arialyy.aria.core.inf.IThreadState; +import com.arialyy.aria.core.inf.IThreadStateManager; import com.arialyy.aria.core.listener.IEventListener; import com.arialyy.aria.core.manager.ThreadTaskManager; import com.arialyy.aria.core.task.IThreadTask; @@ -39,9 +39,10 @@ import java.util.concurrent.TimeUnit; * 3、创建文件信息获取器,获取文件信息,根据文件信息执行任务 * 4、创建线程任务执行下载、上传操作 */ -public abstract class AbsLoader implements ILoaderVisitor, ILoader { - protected final String TAG; - protected IEventListener mListener; +public abstract class AbsNormalLoader implements ILoaderVisitor, ILoader { + protected final String TAG = CommonUtil.getClassName(getClass()); + ; + private IEventListener mListener; protected AbsTaskWrapper mTaskWrapper; protected File mTempFile; @@ -53,32 +54,34 @@ public abstract class AbsLoader implements ILoaderVisitor, ILoader { */ private long mUpdateInterval = 1000; protected TaskRecord mRecord; - private boolean isCancel = false, isStop = false; + protected boolean isCancel = false, isStop = false; private boolean isRuning = false; - private Looper mLooper; protected IRecordHandler mRecordHandler; - protected IThreadState mStateManager; + protected IThreadStateManager mStateManager; protected IInfoTask mInfoTask; protected IThreadTaskBuilder mTTBuilder; - protected AbsLoader(AbsTaskWrapper wrapper, IEventListener listener) { + protected AbsNormalLoader(AbsTaskWrapper wrapper, IEventListener listener) { mListener = listener; mTaskWrapper = wrapper; - TAG = CommonUtil.getClassName(getClass()); } /** * 启动线程任务 */ - protected abstract void handleTask(); + protected abstract void handleTask(Looper looper); /** * 获取文件长度 */ public abstract long getFileSize(); - public IThreadState getStateManager() { + protected IEventListener getListener() { + return mListener; + } + + protected IThreadStateManager getStateManager() { return mStateManager; } @@ -119,22 +122,16 @@ public abstract class AbsLoader implements ILoaderVisitor, ILoader { if (isBreak()) { return; } + Looper.prepare(); + Looper looper = Looper.myLooper(); isRuning = true; resetState(); onPostPre(); - handleTask(); startTimer(); + handleTask(looper); Looper.loop(); } - @Override public Looper getLooper() { - if (mLooper == null) { - Looper.prepare(); - mLooper = Looper.myLooper(); - } - return mLooper; - } - /** * 预处理完成 */ @@ -201,13 +198,14 @@ public abstract class AbsLoader implements ILoaderVisitor, ILoader { mUpdateInterval = interval; } + @Override public synchronized boolean isRunning() { boolean b = ThreadTaskManager.getInstance().taskIsRunning(mTaskWrapper.getKey()); //ALog.d(TAG, "isRunning = " + b); return b && isRuning; } - final public synchronized void cancel() { + @Override final public synchronized void cancel() { if (isCancel) { ALog.d(TAG, String.format("任务【%s】正在删除,删除任务失败", mTaskWrapper.getKey())); return; @@ -300,7 +298,7 @@ public abstract class AbsLoader implements ILoaderVisitor, ILoader { /** * 检查组件: {@link #mRecordHandler}、{@link #mInfoTask}、{@link #mStateManager}、{@link #mTTBuilder} */ - private void checkComponent() { + protected void checkComponent() { if (mRecordHandler == null) { throw new NullPointerException("任务记录组件为空"); } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/AbsNormalLoaderUtil.java b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/AbsNormalLoaderUtil.java index e31b0c81..ab03df26 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/AbsNormalLoaderUtil.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/AbsNormalLoaderUtil.java @@ -20,6 +20,7 @@ import com.arialyy.aria.core.inf.IUtil; import com.arialyy.aria.core.listener.IEventListener; import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.exception.BaseException; +import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.CommonUtil; /** @@ -29,7 +30,7 @@ import com.arialyy.aria.util.CommonUtil; public abstract class AbsNormalLoaderUtil implements IUtil { protected String TAG = CommonUtil.getClassName(getClass()); private IEventListener mListener; - protected AbsLoader mLoader; + protected AbsNormalLoader mLoader; private AbsTaskWrapper mTaskWrapper; private boolean isStop = false, isCancel = false; @@ -42,12 +43,12 @@ public abstract class AbsNormalLoaderUtil implements IUtil { /** * 获取加载器 */ - public abstract AbsLoader getLoader(); + public abstract AbsNormalLoader getLoader(); /** * 获取构造器 */ - public abstract LoaderStructure getLoaderStructure(); + public abstract LoaderStructure BuildLoaderStructure(); @Override public String getKey() { return mTaskWrapper.getKey(); @@ -99,6 +100,7 @@ public abstract class AbsNormalLoaderUtil implements IUtil { */ @Override public void start() { if (isStop || isCancel) { + ALog.w(TAG, "启动任务失败,任务已停止或已取消"); return; } mListener.onPre(); @@ -112,7 +114,7 @@ public abstract class AbsNormalLoaderUtil implements IUtil { // mDownloader.create(); //} - getLoaderStructure(); + BuildLoaderStructure(); new Thread(mLoader).start(); onStart(); diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/AbsNormalTTBuilder.java b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/AbsNormalTTBuilder.java index a483ecd3..d775f3e2 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/AbsNormalTTBuilder.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/AbsNormalTTBuilder.java @@ -1,13 +1,12 @@ package com.arialyy.aria.core.loader; import android.os.Handler; -import android.os.Looper; import com.arialyy.aria.core.TaskRecord; import com.arialyy.aria.core.ThreadRecord; import com.arialyy.aria.core.common.AbsNormalEntity; import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.download.DGTaskWrapper; -import com.arialyy.aria.core.inf.IThreadState; +import com.arialyy.aria.core.inf.IThreadStateManager; import com.arialyy.aria.core.task.IThreadTask; import com.arialyy.aria.core.task.IThreadTaskAdapter; import com.arialyy.aria.core.task.ThreadTask; @@ -36,7 +35,7 @@ public abstract class AbsNormalTTBuilder implements IThreadTaskBuilder { mTempFile = new File(((AbsNormalEntity) wrapper.getEntity()).getFilePath()); } - protected File getTempFile(){ + protected File getTempFile() { return mTempFile; } @@ -111,7 +110,7 @@ public abstract class AbsNormalTTBuilder implements IThreadTaskBuilder { long fileLength = getEntity().getFileSize(); long blockSize = fileLength / mTotalThreadNum; long currentProgress = 0; - List threadTasks = new ArrayList<>(); + List threadTasks = new ArrayList<>(mTotalThreadNum); mRecord.fileLength = fileLength; if (mWrapper.isNewTask() && !handleNewTask(mRecord, mTotalThreadNum)) { @@ -132,7 +131,7 @@ public abstract class AbsNormalTTBuilder implements IThreadTaskBuilder { if (tr.isComplete) {//该线程已经完成 currentProgress += endL - startL; ALog.d(TAG, String.format("任务【%s】线程__%s__已完成", mWrapper.getKey(), i)); - mStateHandler.obtainMessage(IThreadState.STATE_COMPLETE).sendToTarget(); + mStateHandler.obtainMessage(IThreadStateManager.STATE_COMPLETE).sendToTarget(); continue; } @@ -162,15 +161,14 @@ public abstract class AbsNormalTTBuilder implements IThreadTaskBuilder { private List handleTask() { if (mWrapper.isSupportBP()) { return handleBreakpoint(); - }else { + } else { return handleNoSupportBP(); } } - @Override public List buildThreadTask(TaskRecord record, Looper looper, - IThreadState stateManager) { + @Override public List buildThreadTask(TaskRecord record, Handler stateHandler) { mRecord = record; - mStateHandler = new Handler(looper, stateManager.getHandlerCallback()); + mStateHandler = stateHandler; mTotalThreadNum = mRecord.threadNum; return handleTask(); } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/ILoader.java b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/ILoader.java index 356cdc08..42895716 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/ILoader.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/ILoader.java @@ -15,12 +15,19 @@ */ package com.arialyy.aria.core.loader; -import android.os.Looper; - -public interface ILoader extends Runnable{ +public interface ILoader extends Runnable { //void start(); + /** + * 任务是否在执行 + * + * @return true 任务执行中 + */ + boolean isRunning(); + + void cancel(); + void stop(); /** @@ -33,6 +40,4 @@ public interface ILoader extends Runnable{ String getKey(); long getCurrentProgress(); - - Looper getLooper(); } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/ILoaderVisitor.java b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/ILoaderVisitor.java index e4d0b84c..0d20b8ed 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/ILoaderVisitor.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/ILoaderVisitor.java @@ -15,7 +15,7 @@ */ package com.arialyy.aria.core.loader; -import com.arialyy.aria.core.inf.IThreadState; +import com.arialyy.aria.core.inf.IThreadStateManager; /** * 加载器访问者 @@ -35,7 +35,7 @@ public interface ILoaderVisitor { /** * 线程状态 */ - void addComponent(IThreadState threadState); + void addComponent(IThreadStateManager threadState); /** * 构造线程任务 diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/IRecordHandler.java b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/IRecordHandler.java index b27b7249..c23c7385 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/IRecordHandler.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/IRecordHandler.java @@ -44,7 +44,7 @@ public interface IRecordHandler extends ILoaderComponent { /** * 获取任务记录 */ - TaskRecord getRecord(); + TaskRecord getRecord(long fileSize); /** * 记录处理前的操作,可用来删除任务记录 diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/IThreadTaskBuilder.java b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/IThreadTaskBuilder.java index bb2a8aa6..2d3b9dd0 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/IThreadTaskBuilder.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/IThreadTaskBuilder.java @@ -15,9 +15,8 @@ */ package com.arialyy.aria.core.loader; -import android.os.Looper; +import android.os.Handler; import com.arialyy.aria.core.TaskRecord; -import com.arialyy.aria.core.inf.IThreadState; import com.arialyy.aria.core.task.IThreadTask; import java.util.List; @@ -29,10 +28,10 @@ public interface IThreadTaskBuilder extends ILoaderComponent { /** * 构造线程任务 */ - List buildThreadTask(TaskRecord record, Looper looper, IThreadState stateManager); + List buildThreadTask(TaskRecord record, Handler stateHandler); /** - * 获取创建的线程任务数,需要先调用{@link #buildThreadTask(TaskRecord, Looper, IThreadState)}方法才能获取创建的线程任务数 + * 获取创建的线程任务数,需要先调用{@link #buildThreadTask(TaskRecord, Handler)}方法才能获取创建的线程任务数 */ int getCreatedThreadNum(); } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/LoaderStructure.java b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/LoaderStructure.java index 5454f294..6dbe330a 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/LoaderStructure.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/LoaderStructure.java @@ -15,7 +15,7 @@ */ package com.arialyy.aria.core.loader; -import com.arialyy.aria.core.inf.IThreadState; +import com.arialyy.aria.core.inf.IThreadStateManager; import java.util.ArrayList; import java.util.List; @@ -33,7 +33,7 @@ public class LoaderStructure { * 将组件加入到集合,必须添加以下集合: * 1 {@link IRecordHandler} * 2 {@link IInfoTask} - * 3 {@link IThreadState} + * 3 {@link IThreadStateManager} * 4 {@link IThreadTaskBuilder} * * @param component 待添加的组件 diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/NormalLoader.java b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/NormalLoader.java index 50755733..aeda85c5 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/NormalLoader.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/NormalLoader.java @@ -15,25 +15,28 @@ */ package com.arialyy.aria.core.loader; +import android.os.Handler; +import android.os.Looper; import com.arialyy.aria.core.common.AbsEntity; import com.arialyy.aria.core.common.AbsNormalEntity; import com.arialyy.aria.core.common.CompleteInfo; import com.arialyy.aria.core.event.EventMsgUtil; -import com.arialyy.aria.core.inf.IThreadState; +import com.arialyy.aria.core.inf.IThreadStateManager; import com.arialyy.aria.core.listener.IDLoadListener; import com.arialyy.aria.core.listener.IEventListener; import com.arialyy.aria.core.manager.ThreadTaskManager; import com.arialyy.aria.core.task.IThreadTask; import com.arialyy.aria.core.wrapper.AbsTaskWrapper; import com.arialyy.aria.exception.BaseException; -import com.arialyy.aria.util.ALog; import java.io.File; /** * 单文件 */ -public class NormalLoader extends AbsLoader { - private int mStartThreadNum; //启动的线程数 +public class NormalLoader extends AbsNormalLoader { + private int startThreadNum; //启动的线程数 + private boolean isComplete = false; + private Looper looper; public NormalLoader(AbsTaskWrapper wrapper, IEventListener listener) { super(wrapper, listener); @@ -57,8 +60,8 @@ public class NormalLoader extends AbsLoader { */ protected void setMaxSpeed(int maxSpeed) { for (IThreadTask threadTask : getTaskList()) { - if (threadTask != null && mStartThreadNum > 0) { - threadTask.setMaxSpeed(maxSpeed / mStartThreadNum); + if (threadTask != null && startThreadNum > 0) { + threadTask.setMaxSpeed(maxSpeed / startThreadNum); } } } @@ -70,8 +73,8 @@ public class NormalLoader extends AbsLoader { @Override protected void onPostPre() { super.onPostPre(); - if (mListener instanceof IDLoadListener) { - ((IDLoadListener) mListener).onPostPre(getEntity().getFileSize()); + if (getListener() instanceof IDLoadListener) { + ((IDLoadListener) getListener()).onPostPre(getEntity().getFileSize()); } File file = new File(getEntity().getFilePath()); if (file.getParentFile() != null && !file.getParentFile().exists()) { @@ -79,35 +82,38 @@ public class NormalLoader extends AbsLoader { } } - /** - * 如果使用"Content-Disposition"中的文件名,需要更新{@link #mTempFile}的路径 - */ - public void updateTempFile() { - if (!mTempFile.getPath().equals(getEntity().getFilePath())) { - boolean b = mTempFile.renameTo(new File(getEntity().getFilePath())); - ALog.d(TAG, String.format("更新tempFile文件名%s", b ? "成功" : "失败")); - } - } + ///** + // * 如果使用"Content-Disposition"中的文件名,需要更新{@link #mTempFile}的路径 + // */ + //public void updateTempFile() { + // if (!mTempFile.getPath().equals(getEntity().getFilePath())) { + // boolean b = mTempFile.renameTo(new File(getEntity().getFilePath())); + // ALog.d(TAG, String.format("更新tempFile文件名%s", b ? "成功" : "失败")); + // } + //} /** * 启动单线程任务 */ @Override - public void handleTask() { - if (isBreak()) { + public void handleTask(Looper looper) { + if (isBreak() || isComplete) { return; } - mStateManager.setLooper(mRecord, getLooper()); + this.looper = looper; mInfoTask.run(); } - private void startThreadTask() { - getTaskList().addAll(mTTBuilder.buildThreadTask(mRecord, getLooper(), mStateManager)); - mStartThreadNum = mTTBuilder.getCreatedThreadNum(); + protected void startThreadTask() { + mRecord = mRecordHandler.getRecord(getFileSize()); + mStateManager.setLooper(mRecord, looper); + getTaskList().addAll(mTTBuilder.buildThreadTask(mRecord, + new Handler(looper, mStateManager.getHandlerCallback()))); + startThreadNum = mTTBuilder.getCreatedThreadNum(); if (mStateManager.getCurrentProgress() > 0) { - mListener.onResume(mStateManager.getCurrentProgress()); + getListener().onResume(mStateManager.getCurrentProgress()); } else { - mListener.onStart(mStateManager.getCurrentProgress()); + getListener().onStart(mStateManager.getCurrentProgress()); } for (IThreadTask threadTask : getTaskList()) { @@ -121,10 +127,10 @@ public class NormalLoader extends AbsLoader { @Override public void addComponent(IRecordHandler recordHandler) { mRecordHandler = recordHandler; - mRecord = mRecordHandler.getRecord(); if (recordHandler.checkTaskCompleted()) { mRecord.deleteData(); - mListener.onComplete(); + isComplete = true; + getListener().onComplete(); } } @@ -136,12 +142,12 @@ public class NormalLoader extends AbsLoader { } @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { - mListener.onFail(needRetry, e); + getListener().onFail(needRetry, e); } }); } - @Override public void addComponent(IThreadState threadState) { + @Override public void addComponent(IThreadStateManager threadState) { mStateManager = threadState; } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/ThreadStateManager.java b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/NormalThreadStateManager.java similarity index 94% rename from PublicComponent/src/main/java/com/arialyy/aria/core/loader/ThreadStateManager.java rename to PublicComponent/src/main/java/com/arialyy/aria/core/loader/NormalThreadStateManager.java index e8bcf1b5..72e6430f 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/ThreadStateManager.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/NormalThreadStateManager.java @@ -20,7 +20,7 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import com.arialyy.aria.core.TaskRecord; -import com.arialyy.aria.core.inf.IThreadState; +import com.arialyy.aria.core.inf.IThreadStateManager; import com.arialyy.aria.core.listener.IEventListener; import com.arialyy.aria.exception.BaseException; import com.arialyy.aria.util.ALog; @@ -32,7 +32,7 @@ import java.util.List; /** * 线程任务管理器,用于处理多线程下载时任务的状态回调 */ -public class ThreadStateManager implements IThreadState { +public class NormalThreadStateManager implements IThreadStateManager { private final String TAG = "ThreadTaskStateManager"; /** @@ -51,7 +51,7 @@ public class ThreadStateManager implements IThreadState { /** * @param listener 任务事件 */ - public ThreadStateManager(IEventListener listener) { + public NormalThreadStateManager(IEventListener listener) { mListener = listener; } @@ -220,6 +220,11 @@ public class ThreadStateManager implements IThreadState { * @return {@code true} 合并成功,{@code false}合并失败 */ private boolean mergeFile() { + if (mTaskRecord.threadNum == 1) { + File partFile = new File(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, 0)); + return partFile.renameTo(new File(mTaskRecord.filePath)); + } + List partPath = new ArrayList<>(); for (int i = 0, len = mTaskRecord.threadNum; i < len; i++) { partPath.add(String.format(IRecordHandler.SUB_PATH, mTaskRecord.filePath, i)); diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/SubLoader.java b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/SubLoader.java new file mode 100644 index 00000000..d5eb3d7d --- /dev/null +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/SubLoader.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) + * + * 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.arialyy.aria.core.loader; + +import android.os.Handler; +import com.arialyy.aria.core.common.AbsEntity; +import com.arialyy.aria.core.common.CompleteInfo; +import com.arialyy.aria.core.inf.IThreadStateManager; +import com.arialyy.aria.core.listener.ISchedulers; +import com.arialyy.aria.core.manager.ThreadTaskManager; +import com.arialyy.aria.core.task.IThreadTask; +import com.arialyy.aria.core.wrapper.AbsTaskWrapper; +import com.arialyy.aria.exception.BaseException; +import com.arialyy.aria.util.ALog; +import com.arialyy.aria.util.CommonUtil; +import java.util.List; + +/** + * 子任务加载器 + */ +public final class SubLoader implements ILoader, ILoaderVisitor { + private String TAG = CommonUtil.getClassName(this); + // 是否需要获取信息 + private boolean needGetInfo = true; + private Handler schedulers; + private boolean isCancel = false, isStop = false; + private AbsTaskWrapper wrapper; + private IInfoTask infoTask; + private IThreadTaskBuilder ttBuild; + private IRecordHandler recordHandler; + private IThreadTask threadTask; + + public SubLoader(AbsTaskWrapper wrapper, Handler schedulers) { + this.wrapper = wrapper; + this.schedulers = schedulers; + } + + private void handlerTask() { + List task = + ttBuild.buildThreadTask(recordHandler.getRecord(wrapper.getEntity().getFileSize()), + schedulers); + if (task == null || task.isEmpty()) { + ALog.e(TAG, "创建子任务的线程任务失败,key:" + getKey()); + //schedulers.obtainMessage(ISchedulers.FAIL, SubLoader.this).sendToTarget(); + return; + } + threadTask = task.get(0); + try { + ThreadTaskManager.getInstance().startThread(getKey(), threadTask); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void setNeedGetInfo(boolean needGetInfo) { + this.needGetInfo = needGetInfo; + } + + public void retryTask() { + try { + if (threadTask != null) { + threadTask.call(); + } else { + ALog.e(TAG, "子任务的线程任务为空"); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override public void stop() { + if (isStop) { + ALog.w(TAG, "子任务已停止"); + return; + } + isStop = true; + threadTask.stop(); + } + + @Override public boolean isRunning() { + return !threadTask.isBreak(); + } + + @Override public void cancel() { + if (isCancel) { + ALog.w(TAG, "子任务已取消"); + return; + } + isCancel = true; + threadTask.cancel(); + } + + @Override public boolean isBreak() { + if (isCancel || isStop) { + ALog.d(TAG, "isCancel = " + isCancel + ", isStop = " + isStop); + ALog.d(TAG, String.format("任务【%s】已停止或取消了", wrapper.getKey())); + return true; + } + return false; + } + + @Override public String getKey() { + return wrapper.getKey(); + } + + /** + * @deprecated 子任务不需要实现这个 + */ + @Deprecated + @Override public long getCurrentProgress() { + return 0; + } + + @Override public void addComponent(IRecordHandler recordHandler) { + this.recordHandler = recordHandler; + } + + @Override public void addComponent(IInfoTask infoTask) { + this.infoTask = infoTask; + infoTask.setCallback(new IInfoTask.Callback() { + @Override public void onSucceed(String key, CompleteInfo info) { + handlerTask(); + } + + @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { + schedulers.obtainMessage(ISchedulers.FAIL, SubLoader.this).sendToTarget(); + } + }); + } + + /** + * @deprecated 子任务不需要实现这个 + */ + @Override public void addComponent(IThreadStateManager threadState) { + // 子任务不需要实现这个 + } + + @Override public void addComponent(IThreadTaskBuilder builder) { + ttBuild = builder; + } + + @Override public void run() { + checkComponent(); + if (isBreak()) { + return; + } + if (needGetInfo) { + infoTask.run(); + } else { + handlerTask(); + } + } + + /** + * 检查组件: {@link #recordHandler}、{@link #infoTask}、{@link #ttBuild} + */ + private void checkComponent() { + if (recordHandler == null) { + throw new NullPointerException("任务记录组件为空"); + } + if (infoTask == null) { + throw new NullPointerException(("文件信息组件为空")); + } + if (ttBuild == null) { + throw new NullPointerException("线程任务组件为空"); + } + } +} diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/ConstantIntercept.java b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/SubTTBuilder.java similarity index 60% rename from PublicComponent/src/main/java/com/arialyy/aria/core/loader/ConstantIntercept.java rename to PublicComponent/src/main/java/com/arialyy/aria/core/loader/SubTTBuilder.java index 16df241a..8ec3fe15 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/loader/ConstantIntercept.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/loader/SubTTBuilder.java @@ -1,4 +1,3 @@ - /* * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) * @@ -16,14 +15,24 @@ */ package com.arialyy.aria.core.loader; -/** - * 用于初始化一些常用的常量 - */ -public final class ConstantIntercept implements ILoaderInterceptor { +import android.os.Handler; +import com.arialyy.aria.core.TaskRecord; +import com.arialyy.aria.core.task.IThreadTask; +import java.util.List; +public class SubTTBuilder implements IThreadTaskBuilder{ - @Override public ILoader intercept(Chain chain) { + + @Override public List buildThreadTask(TaskRecord record, Handler stateHandler) { return null; } + + @Override public int getCreatedThreadNum() { + return 1; + } + + @Override public void accept(ILoaderVisitor visitor) { + visitor.addComponent(this); + } } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/task/AbsNormalLoaderAdapter.java b/PublicComponent/src/main/java/com/arialyy/aria/core/task/AbsNormalLoaderAdapter.java deleted file mode 100644 index 2865781b..00000000 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/task/AbsNormalLoaderAdapter.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) - * - * 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.arialyy.aria.core.task; - -import com.arialyy.aria.core.common.AbsNormalEntity; -import com.arialyy.aria.core.loader.ILoaderAdapter; -import com.arialyy.aria.core.wrapper.ITaskWrapper; -import com.arialyy.aria.util.CommonUtil; -import java.io.File; - -/** - * 单文件任务适配器 - * - * @Author lyy - * @Date 2019-09-19 - */ -public abstract class AbsNormalLoaderAdapter implements ILoaderAdapter { - protected String TAG = CommonUtil.getClassName(getClass()); - - private ITaskWrapper mWrapper; - private File mTempFile; - - public AbsNormalLoaderAdapter(ITaskWrapper wrapper) { - mWrapper = wrapper; - mTempFile = new File(((AbsNormalEntity) wrapper.getEntity()).getFilePath()); - } - - public ITaskWrapper getWrapper() { - return mWrapper; - } - - public File getTempFile() { - return mTempFile; - } -} diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/task/IThreadTaskObserver.java b/PublicComponent/src/main/java/com/arialyy/aria/core/task/IThreadTaskObserver.java index dd2b14a1..3716b1e9 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/task/IThreadTaskObserver.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/task/IThreadTaskObserver.java @@ -16,7 +16,7 @@ package com.arialyy.aria.core.task; import android.os.Bundle; -import com.arialyy.aria.core.inf.IThreadState; +import com.arialyy.aria.core.inf.IThreadStateManager; import com.arialyy.aria.exception.BaseException; /** @@ -30,7 +30,7 @@ public interface IThreadTaskObserver { /** * 更新所有状态 * - * @param state state {@link IThreadState#STATE_STOP}.. + * @param state state {@link IThreadStateManager#STATE_STOP}.. */ void updateState(int state, Bundle bundle); diff --git a/PublicComponent/src/main/java/com/arialyy/aria/core/task/ThreadTask.java b/PublicComponent/src/main/java/com/arialyy/aria/core/task/ThreadTask.java index d86fa8b8..e8cab93c 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/core/task/ThreadTask.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/core/task/ThreadTask.java @@ -24,7 +24,7 @@ import com.arialyy.aria.core.AriaConfig; import com.arialyy.aria.core.ThreadRecord; import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.inf.IEntity; -import com.arialyy.aria.core.inf.IThreadState; +import com.arialyy.aria.core.inf.IThreadStateManager; import com.arialyy.aria.core.listener.ISchedulers; import com.arialyy.aria.core.manager.ThreadTaskManager; import com.arialyy.aria.core.wrapper.AbsTaskWrapper; @@ -168,7 +168,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { taskBreak = true; if (mTaskWrapper.isSupportBP()) { final long currentTemp = mRangeProgress; - updateState(IThreadState.STATE_STOP, null); + updateState(IThreadStateManager.STATE_STOP, null); ALog.d(TAG, String.format("任务【%s】thread__%s__中断【停止位置:%s】", getFileName(), mRecord.threadId, currentTemp)); writeConfig(false, currentTemp); @@ -238,7 +238,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { @Override public void stop() { isStop = true; - updateState(IThreadState.STATE_STOP, null); + updateState(IThreadStateManager.STATE_STOP, null); if (mTaskWrapper.getRequestType() == ITaskWrapper.M3U8_VOD) { writeConfig(false, getConfig().tempFile.length()); ALog.i(TAG, String.format("任务【%s】已停止", getFileName())); @@ -258,20 +258,35 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { /** * 发送状态给状态处理器 * - * @param state {@link IThreadState#STATE_STOP}.. + * @param state {@link IThreadStateManager#STATE_STOP}.. * @param bundle 而外数据 */ @Override public synchronized void updateState(int state, Bundle bundle) { Message msg = mStateHandler.obtainMessage(); + msg.what = state; - if (state != IThreadState.STATE_UPDATE_PROGRESS) { - msg.obj = this; + if (bundle != null) { + msg.setData(bundle); + } + int reqType = mTaskWrapper.getRequestType(); + if (reqType == ITaskWrapper.M3U8_VOD || reqType == ITaskWrapper.M3U8_LIVE) { + sendM3U8Info(state, msg); + } + + Thread loopThread = mStateHandler.getLooper().getThread(); + if (!loopThread.isAlive() || loopThread.isInterrupted()) { + return; } + msg.sendToTarget(); + } - if ((state == IThreadState.STATE_COMPLETE || state == IThreadState.STATE_FAIL) - && (mTaskWrapper.getRequestType() == AbsTaskWrapper.M3U8_VOD - || mTaskWrapper.getRequestType() == AbsTaskWrapper.M3U8_LIVE)) { + private void sendM3U8Info(int state, Message msg) { + if (state != IThreadStateManager.STATE_UPDATE_PROGRESS) { + msg.obj = this; + } + Bundle bundle = msg.getData(); + if ((state == IThreadStateManager.STATE_COMPLETE || state == IThreadStateManager.STATE_FAIL)) { if (bundle == null) { bundle = new Bundle(); } @@ -279,20 +294,12 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { bundle.putString(ISchedulers.DATA_M3U8_PEER_PATH, getConfig().tempFile.getPath()); bundle.putInt(ISchedulers.DATA_M3U8_PEER_INDEX, getConfig().peerIndex); } - if (bundle != null) { - msg.setData(bundle); - } - Thread loopThread = mStateHandler.getLooper().getThread(); - if (!loopThread.isAlive() || loopThread.isInterrupted()) { - return; - } - msg.sendToTarget(); } @Override public synchronized void updateCompleteState() { ALog.i(TAG, String.format("任务【%s】线程__%s__下载完毕", getTaskWrapper().getKey(), mRecord.threadId)); writeConfig(true, mRecord.endLocation); - updateState(IThreadState.STATE_COMPLETE, null); + updateState(IThreadStateManager.STATE_COMPLETE, null); } /** @@ -311,7 +318,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { if (!loopThread.isAlive() || loopThread.isInterrupted()) { return; } - mStateHandler.obtainMessage(IThreadState.STATE_RUNNING, len).sendToTarget(); + mStateHandler.obtainMessage(IThreadStateManager.STATE_RUNNING, len).sendToTarget(); if (System.currentTimeMillis() - mLastSaveTime > 5000 && mRangeProgress < mRecord.endLocation) { mLastSaveTime = System.currentTimeMillis(); @@ -332,7 +339,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { @Override public void cancel() { isCancel = true; - updateState(IThreadState.STATE_CANCEL, null); + updateState(IThreadStateManager.STATE_CANCEL, null); ALog.d(TAG, String.format("任务【%s】thread__%s__取消", getFileName(), mRecord.threadId)); } @@ -396,8 +403,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { return; } if (mFailTimes < RETRY_NUM && needRetry && (NetUtils.isConnected( - AriaConfig.getInstance().getAPP()) - || isNotNetRetry) && !isBreak()) { + AriaConfig.getInstance().getAPP()) || isNotNetRetry) && !isBreak()) { ALog.w(TAG, String.format("分块【%s】正在重试", getFileName())); mFailTimes++; handleBlockRecord(); @@ -435,7 +441,7 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { } else if (blockFileLen < mRecord.blockLen) { mRecord.startLocation = mRecord.endLocation - mRecord.blockLen + blockFileLen; mRecord.isComplete = false; - updateState(IThreadState.STATE_UPDATE_PROGRESS, null); + updateState(IThreadStateManager.STATE_UPDATE_PROGRESS, null); ALog.i(TAG, String.format("修正分块【%s】记录,开始位置:%s,结束位置:%s", temp.getName(), mRecord.startLocation, mRecord.endLocation)); @@ -453,12 +459,12 @@ public class ThreadTask implements IThreadTask, IThreadTaskObserver { */ private void sendFailMsg(BaseException e, boolean needRetry) { Bundle b = new Bundle(); - b.putBoolean(IThreadState.KEY_RETRY, needRetry); + b.putBoolean(IThreadStateManager.KEY_RETRY, needRetry); if (e != null) { - b.putSerializable(IThreadState.KEY_ERROR_INFO, e); - updateState(IThreadState.STATE_FAIL, b); + b.putSerializable(IThreadStateManager.KEY_ERROR_INFO, e); + updateState(IThreadStateManager.STATE_FAIL, b); } else { - updateState(IThreadState.STATE_FAIL, b); + updateState(IThreadStateManager.STATE_FAIL, b); } } diff --git a/PublicComponent/src/main/java/com/arialyy/aria/orm/DBConfig.java b/PublicComponent/src/main/java/com/arialyy/aria/orm/DBConfig.java index 641bd1f1..e7e3ea28 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/orm/DBConfig.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/orm/DBConfig.java @@ -34,7 +34,7 @@ class DBConfig { static boolean DEBUG = false; static Map> mapping = new LinkedHashMap<>(); static String DB_NAME; - static int VERSION = 57; + static int VERSION = 58; /** * 是否将数据库保存在Sd卡,{@code true} 是 diff --git a/PublicComponent/src/main/java/com/arialyy/aria/orm/SqlHelper.java b/PublicComponent/src/main/java/com/arialyy/aria/orm/SqlHelper.java index 6cfd18cd..ed785f89 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/orm/SqlHelper.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/orm/SqlHelper.java @@ -28,6 +28,7 @@ import com.arialyy.aria.util.ALog; import java.io.File; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -163,7 +164,49 @@ final class SqlHelper extends SQLiteOpenHelper { for (String tableName : tables) { Class clazz = DBConfig.mapping.get(tableName); if (SqlUtil.tableExists(db, clazz)) { - //修改表名为中介表名 + // ----------- 1、获取旧表字段、新表字段 + Cursor columnC = + db.rawQuery(String.format("PRAGMA table_info(%s)", tableName), null); + + // 获取新表的所有字段名称 + List newTabColumns = SqlUtil.getColumns(clazz); + // 获取旧表的所有字段名称 + List oldTabColumns = new ArrayList<>(); + + while (columnC.moveToNext()) { + String columnName = columnC.getString(columnC.getColumnIndex("name")); + oldTabColumns.add(columnName); + } + columnC.close(); + + // ----------- 2、为防止字段增加失败的情况,先给旧表增加字段 + List newAddColum = getNewColumn(newTabColumns, oldTabColumns); + // 删除重命名的字段 + Map modifyMap = null; + if (modifyColumns != null){ + modifyMap = modifyColumns.get(tableName); + if (modifyMap != null){ + Iterator it = newAddColum.iterator(); + while (it.hasNext()){ + String s = it.next(); + if (modifyMap.get(s) != null){ + it.remove(); + } + } + } + } + + // 给旧表增加字段,防止新增字段失败 + if (newAddColum.size() > 0){ + String sql = "ALTER TABLE %s ADD COLUMN %s %s"; + for (String nc : newAddColum){ + String temp = String.format(sql, tableName, nc, SqlUtil.getColumnTypeByFieldName(clazz, nc)); + ALog.d(TAG, "添加表字段的sql:" + temp); + db.execSQL(temp); + } + } + + // ----------- 3、将旧表备份下,并创建新表 String alertSql = String.format("ALTER TABLE %s RENAME TO %s_temp", tableName, tableName); db.execSQL(alertSql); @@ -176,28 +219,15 @@ final class SqlHelper extends SQLiteOpenHelper { long count = cursor.getLong(0); cursor.close(); - // 复制数据 + // ----------- 4、将旧表数据复制到新表 if (count > 0) { - Cursor columnC = - db.rawQuery(String.format("PRAGMA table_info(%s_temp)", tableName), null); - - // 获取新表的所有字段名称 - List newTabColumns = SqlUtil.getColumns(clazz); - // 获取旧表的所有字段名称 - List oldTabColumns = new ArrayList<>(); - - while (columnC.moveToNext()) { - String columnName = columnC.getString(columnC.getColumnIndex("name")); - oldTabColumns.add(columnName); - } - columnC.close(); // 旧表需要删除的字段,删除旧表有而新表没的字段 List diffTab = getDiffColumn(newTabColumns, oldTabColumns); StringBuilder params = new StringBuilder(); // 需要修改的列名映射表 - Map modifyMap = null; + //Map modifyMap = null; if (modifyColumns != null) { modifyMap = modifyColumns.get(tableName); } @@ -227,11 +257,11 @@ final class SqlHelper extends SQLiteOpenHelper { String insertSql = String.format("INSERT INTO %s (%s) SELECT %s FROM %s_temp", tableName, newParamStr, oldParamStr, tableName); - ALog.d(TAG, "insertSql = " + insertSql); + ALog.d(TAG, "恢复数据的sql:" + insertSql); db.execSQL(insertSql); } - //删除中介表 + // ----------- 5、删除备份的表 SqlUtil.dropTable(db, tableName + "_temp"); } else { SqlUtil.createTable(db, clazz); @@ -258,6 +288,19 @@ final class SqlHelper extends SQLiteOpenHelper { return temp; } + /** + * 获取新增字段 + * + * @param newTab 新表字段 + * @param oldTab 就表字段 + * @return 新表有而旧表没的字段 + */ + private List getNewColumn(List newTab, List oldTab) { + List temp = new ArrayList<>(newTab); + temp.removeAll(oldTab); + return temp; + } + /** * 给TaskRecord 增加任务类型 */ diff --git a/PublicComponent/src/main/java/com/arialyy/aria/orm/SqlUtil.java b/PublicComponent/src/main/java/com/arialyy/aria/orm/SqlUtil.java index e3141c6d..ff173eb2 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/orm/SqlUtil.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/orm/SqlUtil.java @@ -240,28 +240,13 @@ final class SqlUtil { continue; } Class type = field.getType(); - sb.append(field.getName()); - if (type == String.class || type.isEnum()) { - sb.append(" VARCHAR"); - } else if (type == int.class || type == Integer.class) { - sb.append(" INTEGER"); - } else if (type == float.class || type == Float.class) { - sb.append(" FLOAT"); - } else if (type == double.class || type == Double.class) { - sb.append(" DOUBLE"); - } else if (type == long.class || type == Long.class) { - sb.append(" BIGINT"); - } else if (type == boolean.class || type == Boolean.class) { - sb.append(" BOOLEAN"); - } else if (type == java.util.Date.class || type == java.sql.Date.class) { - sb.append(" DATA"); - } else if (type == byte.class || type == Byte.class) { - sb.append(" BLOB"); - } else if (type == Map.class || type == List.class) { - sb.append(" TEXT"); - } else { + String columnType = getColumnType(type); + if (columnType == null) { continue; } + sb.append(field.getName()); + sb.append(" ").append(columnType); + if (SqlUtil.isPrimary(field)) { Primary pk = field.getAnnotation(Primary.class); sb.append(" PRIMARY KEY"); @@ -315,10 +300,51 @@ final class SqlUtil { String str = sb.toString(); str = str.substring(0, str.length() - 1) + ");"; + ALog.d(TAG, "创建表的sql:" + str); db.execSQL(str); } } + /** + * 根据字段名获取字段类型 + */ + static String getColumnTypeByFieldName(Class tabClass, String fieldName) { + List fields = CommonUtil.getAllFields(tabClass); + for (Field field : fields) { + if (field.getName().equals(fieldName)) { + return getColumnType(field.getType()); + } + } + return null; + } + + /** + * 获取字段类型 + */ + static String getColumnType(Class fieldtype) { + if (fieldtype == String.class || fieldtype.isEnum()) { + return "VARCHAR"; + } else if (fieldtype == int.class || fieldtype == Integer.class) { + return "INTEGER"; + } else if (fieldtype == float.class || fieldtype == Float.class) { + return "FLOAT"; + } else if (fieldtype == double.class || fieldtype == Double.class) { + return "DOUBLE"; + } else if (fieldtype == long.class || fieldtype == Long.class) { + return "BIGINT"; + } else if (fieldtype == boolean.class || fieldtype == Boolean.class) { + return "BOOLEAN"; + } else if (fieldtype == java.util.Date.class || fieldtype == java.sql.Date.class) { + return "DATA"; + } else if (fieldtype == byte.class || fieldtype == Byte.class) { + return "BLOB"; + } else if (fieldtype == Map.class || fieldtype == List.class) { + return "TEXT"; + } else { + return null; + } + } + /** * URL编码字符串 * diff --git a/PublicComponent/src/main/java/com/arialyy/aria/util/ComponentUtil.java b/PublicComponent/src/main/java/com/arialyy/aria/util/ComponentUtil.java index 5ea85006..1bc3b215 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/util/ComponentUtil.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/util/ComponentUtil.java @@ -121,10 +121,10 @@ public class ComponentUtil { className = "com.arialyy.aria.http.upload.HttpULoaderUtil"; break; case ITaskWrapper.D_FTP_DIR: - className = "com.arialyy.aria.ftp.download.FtpDirDLoaderUtil"; + className = "com.arialyy.aria.ftp.download.FtpDGLoaderUtil"; break; case ITaskWrapper.DG_HTTP: - className = "com.arialyy.aria.http.download.DGroupLoaderUtil"; + className = "com.arialyy.aria.http.download.HttpDGLoaderUtil"; break; } if (className == null) { diff --git a/PublicComponent/src/main/java/com/arialyy/aria/util/FileUtil.java b/PublicComponent/src/main/java/com/arialyy/aria/util/FileUtil.java index f954c7f9..b5c8bd26 100644 --- a/PublicComponent/src/main/java/com/arialyy/aria/util/FileUtil.java +++ b/PublicComponent/src/main/java/com/arialyy/aria/util/FileUtil.java @@ -374,6 +374,76 @@ public class FileUtil { } } + /** + * 检查内存空间是否充足 + * + * @param path 文件路径 + * @param fileSize 下载的文件的大小 + * @return true 空间足够 + */ + public static boolean checkMemorySpace(String path, long fileSize) { + File temp = new File(path); + if (!temp.exists()){ + if (!temp.getParentFile().exists()){ + FileUtil.createDir(temp.getParentFile().getPath()); + } + path = temp.getParentFile().getPath(); + } + + StatFs stat = new StatFs(path); + long blockSize = stat.getBlockSize(); + long availableBlocks = stat.getAvailableBlocks(); + return fileSize <= availableBlocks * blockSize; + } + + /** + * 读取下载配置文件 + */ + public static Properties loadConfig(File file) { + Properties properties = new Properties(); + FileInputStream fis = null; + if (!file.exists()) { + createFile(file.getPath()); + } + try { + fis = new FileInputStream(file); + properties.load(fis); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (fis != null) { + fis.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return properties; + } + + /** + * 保存配置文件 + */ + public static void saveConfig(File file, Properties properties) { + FileOutputStream fos = null; + try { + fos = new FileOutputStream(file, false); + properties.store(fos, null); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (fos != null) { + fos.flush(); + fos.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + /** * 检查SD内存空间是否充足 * @@ -381,7 +451,8 @@ public class FileUtil { * @param fileSize 文件大小 * @return {@code false} 内存空间不足,{@code true}内存空间足够 */ - public static boolean checkSDMemorySpace(String filePath, long fileSize) { + @Deprecated + private static boolean checkSDMemorySpace(String filePath, long fileSize) { List dirs = FileUtil.getSDPathList(AriaConfig.getInstance().getAPP()); if (dirs == null || dirs.isEmpty()) { return true; @@ -402,7 +473,7 @@ public class FileUtil { * @param sdcardPath sdcard 根路径 * @return 单位为:byte */ - public static long getAvailableExternalMemorySize(String sdcardPath) { + private static long getAvailableExternalMemorySize(String sdcardPath) { StatFs stat = new StatFs(sdcardPath); long blockSize = stat.getBlockSize(); long availableBlocks = stat.getAvailableBlocks(); @@ -415,7 +486,7 @@ public class FileUtil { * @param sdcardPath sdcard 根路径 * @return 单位为:byte */ - public static long getTotalExternalMemorySize(String sdcardPath) { + private static long getTotalExternalMemorySize(String sdcardPath) { StatFs stat = new StatFs(sdcardPath); long blockSize = stat.getBlockSize(); long totalBlocks = stat.getBlockCount(); @@ -425,13 +496,11 @@ public class FileUtil { /** * 获取SD卡目录列表 */ - public static List getSDPathList(Context context) { + private static List getSDPathList(Context context) { List paths = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { try { paths = getVolumeList(context); - } catch (ClassNotFoundException e) { - e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { @@ -447,59 +516,11 @@ public class FileUtil { return paths; } - /** - * 读取下载配置文件 - */ - public static Properties loadConfig(File file) { - Properties properties = new Properties(); - FileInputStream fis = null; - if (!file.exists()) { - createFile(file.getPath()); - } - try { - fis = new FileInputStream(file); - properties.load(fis); - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - if (fis != null) { - fis.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - return properties; - } - - /** - * 保存配置文件 - */ - public static void saveConfig(File file, Properties properties) { - FileOutputStream fos = null; - try { - fos = new FileOutputStream(file, false); - properties.store(fos, null); - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - if (fos != null) { - fos.flush(); - fos.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - } - /** * getSDPathList */ private static List getVolumeList(final Context context) - throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { List pathList = new ArrayList<>(); @@ -589,7 +610,7 @@ public class FileUtil { * * @return paths to all available SD-Cards in the system (include emulated) */ - public static List getStorageDirectories() { + private static List getStorageDirectories() { // Final set of paths final List rv = new ArrayList<>(); // Primary physical SD-CARD (not emulated) diff --git a/SFtpComponent/src/main/java/com/arialyy/aria/sftp/SFtpInfoThread.java b/SFtpComponent/src/main/java/com/arialyy/aria/sftp/SFtpInfoThread.java index cf517381..08827df0 100644 --- a/SFtpComponent/src/main/java/com/arialyy/aria/sftp/SFtpInfoThread.java +++ b/SFtpComponent/src/main/java/com/arialyy/aria/sftp/SFtpInfoThread.java @@ -1,100 +1,100 @@ -/* - * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) - * - * 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.arialyy.aria.sftp; - -import com.arialyy.aria.core.AriaConfig; -import com.arialyy.aria.core.FtpUrlEntity; -import com.arialyy.aria.core.common.AbsNormalEntity; -import com.arialyy.aria.core.inf.OnFileInfoCallback; -import com.arialyy.aria.core.upload.UploadEntity; -import com.arialyy.aria.core.wrapper.AbsTaskWrapper; -import com.arialyy.aria.ftp.FtpTaskOption; -import com.arialyy.aria.util.ALog; -import com.arialyy.aria.util.CommonUtil; -import com.jcraft.jsch.ChannelSftp; -import com.jcraft.jsch.JSchException; -import com.jcraft.jsch.SftpException; -import java.util.Vector; - -/** - * https://cloud.tencent.com/developer/article/1354612 - * - * @author lyy - */ -public class SFtpInfoThread> - implements Runnable { - - private final String TAG = CommonUtil.getClassName(getClass()); - protected ENTITY mEntity; - protected TASK_WRAPPER mTaskWrapper; - protected FtpTaskOption mTaskOption; - private int mConnectTimeOut; - protected OnFileInfoCallback mCallback; - protected long mSize = 0; - protected String charSet = "UTF-8"; - private boolean isUpload = false; - private SFtpUtil mSFtpUtil; - private BaseInfoThreadAdapter mAdapter; - - public SFtpInfoThread(SFtpUtil ftpUtil, TASK_WRAPPER taskWrapper, - OnFileInfoCallback callback) { - mSFtpUtil = ftpUtil; - mTaskWrapper = taskWrapper; - mEntity = taskWrapper.getEntity(); - mTaskOption = (FtpTaskOption) taskWrapper.getTaskOption(); - mConnectTimeOut = AriaConfig.getInstance().getDConfig().getConnectTimeOut(); - mCallback = callback; - if (mEntity instanceof UploadEntity) { - isUpload = true; - } - } - - public void setAdapter(BaseInfoThreadAdapter adapter) { - mAdapter = adapter; - } - - @Override public void run() { - if (mAdapter == null) { - ALog.e(TAG, "adapter为空"); - return; - } - try { - ChannelSftp channelSftp = - (ChannelSftp) mSFtpUtil.getSession().openChannel(SFtpUtil.CMD_TYPE_SFTP); - Vector files = channelSftp.ls(getUrlEntity().remotePath); - - if (files.isEmpty()) { - ALog.e(TAG, String.format("路径【%s】没有文件", getUrlEntity().remotePath)); - mCallback.onFail(mEntity, null, false); - return; - } - - if (!mAdapter.handlerFile(files)) { - ALog.e(TAG, "文件处理失败"); - mCallback.onFail(mEntity, null, false); - return; - } - } catch (JSchException ex) { - ex.printStackTrace(); - } catch (SftpException e) { - e.printStackTrace(); - } - } - - private FtpUrlEntity getUrlEntity() { - return mTaskOption.getUrlEntity(); - } -} +///* +// * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) +// * +// * 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.arialyy.aria.sftp; +// +//import com.arialyy.aria.core.AriaConfig; +//import com.arialyy.aria.core.FtpUrlEntity; +//import com.arialyy.aria.core.common.AbsNormalEntity; +//import com.arialyy.aria.core.inf.OnFileInfoCallback; +//import com.arialyy.aria.core.upload.UploadEntity; +//import com.arialyy.aria.core.wrapper.AbsTaskWrapper; +//import com.arialyy.aria.ftp.FtpTaskOption; +//import com.arialyy.aria.util.ALog; +//import com.arialyy.aria.util.CommonUtil; +//import com.jcraft.jsch.ChannelSftp; +//import com.jcraft.jsch.JSchException; +//import com.jcraft.jsch.SftpException; +//import java.util.Vector; +// +///** +// * https://cloud.tencent.com/developer/article/1354612 +// * +// * @author lyy +// */ +//public class SFtpInfoThread> +// implements Runnable { +// +// private final String TAG = CommonUtil.getClassName(getClass()); +// protected ENTITY mEntity; +// protected TASK_WRAPPER mTaskWrapper; +// protected FtpTaskOption mTaskOption; +// private int mConnectTimeOut; +// protected OnFileInfoCallback mCallback; +// protected long mSize = 0; +// protected String charSet = "UTF-8"; +// private boolean isUpload = false; +// private SFtpUtil mSFtpUtil; +// private BaseInfoThreadAdapter mAdapter; +// +// public SFtpInfoThread(SFtpUtil ftpUtil, TASK_WRAPPER taskWrapper, +// OnFileInfoCallback callback) { +// mSFtpUtil = ftpUtil; +// mTaskWrapper = taskWrapper; +// mEntity = taskWrapper.getEntity(); +// mTaskOption = (FtpTaskOption) taskWrapper.getTaskOption(); +// mConnectTimeOut = AriaConfig.getInstance().getDConfig().getConnectTimeOut(); +// mCallback = callback; +// if (mEntity instanceof UploadEntity) { +// isUpload = true; +// } +// } +// +// public void setAdapter(BaseInfoThreadAdapter adapter) { +// mAdapter = adapter; +// } +// +// @Override public void run() { +// if (mAdapter == null) { +// ALog.e(TAG, "adapter为空"); +// return; +// } +// try { +// ChannelSftp channelSftp = +// (ChannelSftp) mSFtpUtil.getSession().openChannel(SFtpUtil.CMD_TYPE_SFTP); +// Vector files = channelSftp.ls(getUrlEntity().remotePath); +// +// if (files.isEmpty()) { +// ALog.e(TAG, String.format("路径【%s】没有文件", getUrlEntity().remotePath)); +// mCallback.onFail(mEntity, null, false); +// return; +// } +// +// if (!mAdapter.handlerFile(files)) { +// ALog.e(TAG, "文件处理失败"); +// mCallback.onFail(mEntity, null, false); +// return; +// } +// } catch (JSchException ex) { +// ex.printStackTrace(); +// } catch (SftpException e) { +// e.printStackTrace(); +// } +// } +// +// private FtpUrlEntity getUrlEntity() { +// return mTaskOption.getUrlEntity(); +// } +//} diff --git a/SFtpComponent/src/main/java/com/arialyy/aria/sftp/download/SFtpDLoaderAdapter.java b/SFtpComponent/src/main/java/com/arialyy/aria/sftp/download/SFtpDLoaderAdapter.java index ba0e61e8..66281eb2 100644 --- a/SFtpComponent/src/main/java/com/arialyy/aria/sftp/download/SFtpDLoaderAdapter.java +++ b/SFtpComponent/src/main/java/com/arialyy/aria/sftp/download/SFtpDLoaderAdapter.java @@ -1,40 +1,40 @@ -/* - * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) - * - * 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.arialyy.aria.sftp.download; - -import com.arialyy.aria.core.common.SubThreadConfig; -import com.arialyy.aria.core.task.IThreadTask; -import com.arialyy.aria.core.task.ThreadTask; -import com.arialyy.aria.core.wrapper.ITaskWrapper; -import com.arialyy.aria.ftp.download.FtpDLoaderAdapter; - -/** - * sftp下载适配器 - * - * @author lyy - */ -final class SFtpDLoaderAdapter extends FtpDLoaderAdapter { - SFtpDLoaderAdapter(ITaskWrapper wrapper) { - super(wrapper); - } - - @Override public IThreadTask createThreadTask(SubThreadConfig config) { - ThreadTask threadTask = new ThreadTask(config); - SFtpDThreadTaskAdapter adapter = new SFtpDThreadTaskAdapter(config); - threadTask.setAdapter(adapter); - return threadTask; - } -} +///* +// * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) +// * +// * 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.arialyy.aria.sftp.download; +// +//import com.arialyy.aria.core.common.SubThreadConfig; +//import com.arialyy.aria.core.task.IThreadTask; +//import com.arialyy.aria.core.task.ThreadTask; +//import com.arialyy.aria.core.wrapper.ITaskWrapper; +//import com.arialyy.aria.ftp.download.FtpDTTBuilder; +// +///** +// * sftp下载适配器 +// * +// * @author lyy +// */ +//final class SFtpDLoaderAdapter extends FtpDTTBuilder { +// SFtpDLoaderAdapter(ITaskWrapper wrapper) { +// super(wrapper); +// } +// +// @Override public IThreadTask createThreadTask(SubThreadConfig config) { +// ThreadTask threadTask = new ThreadTask(config); +// SFtpDThreadTaskAdapter adapter = new SFtpDThreadTaskAdapter(config); +// threadTask.setAdapter(adapter); +// return threadTask; +// } +//} diff --git a/SFtpComponent/src/main/java/com/arialyy/aria/sftp/download/SFtpDLoaderUtil.java b/SFtpComponent/src/main/java/com/arialyy/aria/sftp/download/SFtpDLoaderUtil.java index 8191cd7d..edc04e40 100644 --- a/SFtpComponent/src/main/java/com/arialyy/aria/sftp/download/SFtpDLoaderUtil.java +++ b/SFtpComponent/src/main/java/com/arialyy/aria/sftp/download/SFtpDLoaderUtil.java @@ -1,75 +1,75 @@ -/* - * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) - * - * 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.arialyy.aria.sftp.download; - -import com.arialyy.aria.core.common.AbsEntity; -import com.arialyy.aria.core.common.CompleteInfo; -import com.arialyy.aria.core.download.DTaskWrapper; -import com.arialyy.aria.core.inf.OnFileInfoCallback; -import com.arialyy.aria.core.listener.IEventListener; -import com.arialyy.aria.core.loader.AbsLoader; -import com.arialyy.aria.core.loader.AbsNormalLoaderUtil; -import com.arialyy.aria.core.loader.NormalLoader; -import com.arialyy.aria.core.wrapper.AbsTaskWrapper; -import com.arialyy.aria.exception.BaseException; -import com.arialyy.aria.ftp.FtpTaskOption; -import com.arialyy.aria.sftp.SFtpInfoThread; -import com.arialyy.aria.sftp.SFtpUtil; - -/** - * sftp下载工具 - * - * @author lyy - */ -public class SFtpDLoaderUtil extends AbsNormalLoaderUtil { - - private SFtpUtil mSftpUtil; - - protected SFtpDLoaderUtil(AbsTaskWrapper wrapper, IEventListener listener) { - super(wrapper, listener); - wrapper.generateTaskOption(FtpTaskOption.class); - FtpTaskOption option = (FtpTaskOption) wrapper.getTaskOption(); - mSftpUtil = new SFtpUtil.Builder() - .setIp(option.getUrlEntity().hostName) - .setPort(Integer.parseInt(option.getUrlEntity().port)) - .setUserName(option.getUrlEntity().user) - .setPassword(option.getUrlEntity().password) - .build(); - } - - @Override protected AbsLoader createLoader() { - NormalLoader loader = new NormalLoader(getListener(), getTaskWrapper()); - loader.setAdapter(new SFtpDLoaderAdapter(getTaskWrapper())); - return loader; - } - - @Override protected Runnable createInfoThread() { - DSFtpInfoThreadAdapter adapter = new DSFtpInfoThreadAdapter((DTaskWrapper) getTaskWrapper()); - SFtpInfoThread infoThread = new SFtpInfoThread<>(mSftpUtil, (DTaskWrapper) getTaskWrapper(), - new OnFileInfoCallback() { - @Override public void onComplete(String key, CompleteInfo info) { - - } - - @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { - - } - }); - infoThread.setAdapter(adapter); - - return infoThread; - } -} +///* +// * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) +// * +// * 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.arialyy.aria.sftp.download; +// +//import com.arialyy.aria.core.common.AbsEntity; +//import com.arialyy.aria.core.common.CompleteInfo; +//import com.arialyy.aria.core.download.DTaskWrapper; +//import com.arialyy.aria.core.inf.OnFileInfoCallback; +//import com.arialyy.aria.core.listener.IEventListener; +//import com.arialyy.aria.core.loader.AbsNormalLoader; +//import com.arialyy.aria.core.loader.AbsNormalLoaderUtil; +//import com.arialyy.aria.core.loader.NormalLoader; +//import com.arialyy.aria.core.wrapper.AbsTaskWrapper; +//import com.arialyy.aria.exception.BaseException; +//import com.arialyy.aria.ftp.FtpTaskOption; +//import com.arialyy.aria.sftp.SFtpInfoThread; +//import com.arialyy.aria.sftp.SFtpUtil; +// +///** +// * sftp下载工具 +// * +// * @author lyy +// */ +//public class SFtpDLoaderUtil extends AbsNormalLoaderUtil { +// +// private SFtpUtil mSftpUtil; +// +// protected SFtpDLoaderUtil(AbsTaskWrapper wrapper, IEventListener listener) { +// super(wrapper, listener); +// wrapper.generateTaskOption(FtpTaskOption.class); +// FtpTaskOption option = (FtpTaskOption) wrapper.getTaskOption(); +// mSftpUtil = new SFtpUtil.Builder() +// .setIp(option.getUrlEntity().hostName) +// .setPort(Integer.parseInt(option.getUrlEntity().port)) +// .setUserName(option.getUrlEntity().user) +// .setPassword(option.getUrlEntity().password) +// .build(); +// } +// +// @Override protected AbsNormalLoader createLoader() { +// NormalLoader loader = new NormalLoader(getListener(), getTaskWrapper()); +// loader.setAdapter(new SFtpDLoaderAdapter(getTaskWrapper())); +// return loader; +// } +// +// @Override protected Runnable createInfoThread() { +// DSFtpInfoThreadAdapter adapter = new DSFtpInfoThreadAdapter((DTaskWrapper) getTaskWrapper()); +// SFtpInfoThread infoThread = new SFtpInfoThread<>(mSftpUtil, (DTaskWrapper) getTaskWrapper(), +// new OnFileInfoCallback() { +// @Override public void onComplete(String key, CompleteInfo info) { +// +// } +// +// @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { +// +// } +// }); +// infoThread.setAdapter(adapter); +// +// return infoThread; +// } +//} diff --git a/app/src/main/assets/aria_config.xml b/app/src/main/assets/aria_config.xml index cb8d1c24..8ac9205c 100644 --- a/app/src/main/assets/aria_config.xml +++ b/app/src/main/assets/aria_config.xml @@ -44,7 +44,7 @@ - + diff --git a/app/src/main/java/com/arialyy/simple/MainActivity.java b/app/src/main/java/com/arialyy/simple/MainActivity.java index cbf32eb2..8ac51204 100644 --- a/app/src/main/java/com/arialyy/simple/MainActivity.java +++ b/app/src/main/java/com/arialyy/simple/MainActivity.java @@ -29,7 +29,6 @@ import androidx.lifecycle.ViewModelProviders; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import com.arialyy.aria.core.AriaManager; import com.arialyy.frame.permission.OnPermissionCallback; import com.arialyy.frame.permission.PermissionManager; import com.arialyy.frame.util.show.T; diff --git a/app/src/main/java/com/arialyy/simple/core/download/FtpDownloadActivity.java b/app/src/main/java/com/arialyy/simple/core/download/FtpDownloadActivity.java index 8efca66d..6f8e28fa 100644 --- a/app/src/main/java/com/arialyy/simple/core/download/FtpDownloadActivity.java +++ b/app/src/main/java/com/arialyy/simple/core/download/FtpDownloadActivity.java @@ -48,7 +48,7 @@ public class FtpDownloadActivity extends BaseActivity getFtpDownloadInfo(Context context) { //String url = AppUtil.getConfigValue(context, FTP_URL_KEY, ftpDefUrl); - String url = "ftp://9.9.9.72:2121/Cyberduck-6.9.4.30164.zip"; + //String url = "ftp://9.9.9.72:2121/Cyberduck-6.9.4.30164.zip"; + String url = "ftp://58.210.178.52:21/battery1.0.0.apk"; String filePath = AppUtil.getConfigValue(context, FTP_PATH_KEY, ftpDefPath); singDownloadInfo = Aria.download(context).getFirstDownloadEntity(url); diff --git a/app/src/main/java/com/arialyy/simple/core/download/SingleTaskActivity.java b/app/src/main/java/com/arialyy/simple/core/download/SingleTaskActivity.java index c6b238f6..ba3e6cd8 100644 --- a/app/src/main/java/com/arialyy/simple/core/download/SingleTaskActivity.java +++ b/app/src/main/java/com/arialyy/simple/core/download/SingleTaskActivity.java @@ -20,6 +20,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.os.StatFs; import android.util.Log; import android.view.Menu; import android.view.MenuItem; @@ -32,7 +33,6 @@ import androidx.lifecycle.ViewModelProviders; import com.arialyy.annotations.Download; import com.arialyy.aria.core.Aria; import com.arialyy.aria.core.common.HttpOption; -import com.arialyy.aria.core.common.RequestEnum; import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.listener.ISchedulers; @@ -40,16 +40,13 @@ import com.arialyy.aria.core.processor.IHttpFileLenAdapter; import com.arialyy.aria.core.task.DownloadTask; import com.arialyy.aria.util.ALog; import com.arialyy.aria.util.CommonUtil; -import com.arialyy.aria.util.FileUtil; import com.arialyy.frame.util.show.T; import com.arialyy.simple.R; import com.arialyy.simple.base.BaseActivity; import com.arialyy.simple.common.ModifyPathDialog; import com.arialyy.simple.common.ModifyUrlDialog; import com.arialyy.simple.databinding.ActivitySingleBinding; -import com.arialyy.simple.util.AppUtil; import java.io.File; -import java.io.IOException; import java.util.List; import java.util.Map; @@ -275,9 +272,9 @@ public class SingleTaskActivity extends BaseActivity { .load(mTaskId) .stop(); } else { - mTaskId = Aria.download(this).load(mTaskId) + Aria.download(this).load(mTaskId) //.updateUrl(mUrl) - .reStart(); + .resume(); } break; case R.id.cancel: diff --git a/app/src/main/java/com/arialyy/simple/core/download/group/GroupModule.java b/app/src/main/java/com/arialyy/simple/core/download/group/GroupModule.java index d35708f4..907e39ce 100644 --- a/app/src/main/java/com/arialyy/simple/core/download/group/GroupModule.java +++ b/app/src/main/java/com/arialyy/simple/core/download/group/GroupModule.java @@ -54,6 +54,13 @@ public class GroupModule extends BaseModule { return names; } + List getSubName1() { + List names = new ArrayList<>(); + String[] str = getContext().getResources().getStringArray(R.array.group_names); + Collections.addAll(names, str); + return names; + } + List getSubName2() { List taskSubFile; taskSubFile = new ArrayList<>(); diff --git a/app/src/main/java/com/arialyy/simple/core/upload/HttpUploadActivity.java b/app/src/main/java/com/arialyy/simple/core/upload/HttpUploadActivity.java index 1413b02d..944a8c8c 100644 --- a/app/src/main/java/com/arialyy/simple/core/upload/HttpUploadActivity.java +++ b/app/src/main/java/com/arialyy/simple/core/upload/HttpUploadActivity.java @@ -43,7 +43,7 @@ public class HttpUploadActivity extends BaseActivity { //private final String FILE_PATH = "/mnt/sdcard/ggsg14.apk"; private final String FILE_PATH = - Environment.getExternalStorageDirectory().getPath() + "/Download/PaNTFS15562.zip"; + Environment.getExternalStorageDirectory().getPath() + "/Download/QQMusic-import-1.2.1.zip"; private UploadEntity mEntity; @Override protected int setLayoutId() { @@ -82,7 +82,7 @@ public class HttpUploadActivity extends BaseActivity { .setParam("params", "bbbbbbbb"); Aria.upload(HttpUploadActivity.this).load(FILE_PATH) //.setUploadUrl("http://lib-test.xzxyun.com:8042/Api/upload?data={\"type\":\"1\",\"fileType\":\".apk\"}") - .setUploadUrl("http://9.9.9.205:5000/upload/") + .setUploadUrl("http://9.9.12.210:5000/upload/") //.setTempUrl("http://192.168.1.6:8080/upload/sign_file/").setAttachment("file") //.addHeader("iplanetdirectorypro", "11a09102fb934ad0bc206f9c611d7933") .option(option) diff --git a/build.gradle b/build.gradle index d82e187d..92fb3cba 100644 --- a/build.gradle +++ b/build.gradle @@ -44,8 +44,8 @@ task clean(type: Delete) { } ext { - versionCode = 382 - versionName = '3.8.2' + versionCode = 383 + versionName = '3.8.3_beta_1' userOrg = 'arialyy' groupId = 'com.arialyy.aria' publishVersion = versionName diff --git a/settings.gradle b/settings.gradle index ac3cec1e..cee643c8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,2 @@ -include ':app', ':Aria', ':AriaAnnotations', ':AriaCompiler', ':AriaFtpPlug', ':AppFrame', ':HttpComponent', ':M3U8Component', ':SFtpComponent', +include ':app', ':Aria', ':AriaAnnotations', ':AriaCompiler', ':AppFrame', ':HttpComponent', ':M3U8Component', ':SFtpComponent', ':FtpComponent', ':PublicComponent'