pull/330/head
AriaLyy 7 years ago
commit 845800814f
  1. 3
      Aria/build.gradle
  2. 2
      Aria/src/main/java/com/arialyy/aria/core/TaskManager.java
  3. 7
      Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java
  4. 18
      Aria/src/main/java/com/arialyy/aria/core/command/normal/NormalCmdFactory.java
  5. 19
      Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
  6. 9
      Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java
  7. 16
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFileer.java
  8. 198
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFtpInfoThread.java
  9. 81
      Aria/src/main/java/com/arialyy/aria/core/common/AbsFtpThreadTask.java
  10. 40
      Aria/src/main/java/com/arialyy/aria/core/common/AbsThreadTask.java
  11. 4
      Aria/src/main/java/com/arialyy/aria/core/common/OnFileInfoCallback.java
  12. 4
      Aria/src/main/java/com/arialyy/aria/core/common/StateConstance.java
  13. 8
      Aria/src/main/java/com/arialyy/aria/core/download/BaseDListener.java
  14. 13
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java
  15. 10
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java
  16. 155
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsFtpInfoThread.java
  17. 71
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/AbsGroupUtil.java
  18. 5
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java
  19. 6
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java
  20. 3
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirDownloadUtil.java
  21. 14
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpDirInfoThread.java
  22. 12
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpFileInfoThread.java
  23. 44
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FtpThreadTask.java
  24. 1
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/HttpFileInfoThread.java
  25. 1
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java
  26. 2
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java
  27. 17
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java
  28. 2
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java
  29. 2
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsUploadTarget.java
  30. 13
      Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java
  31. 16
      Aria/src/main/java/com/arialyy/aria/core/queue/pool/BaseExecutePool.java
  32. 27
      Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java
  33. 4
      Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadGroupSchedulers.java
  34. 4
      Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadSchedulers.java
  35. 4
      Aria/src/main/java/com/arialyy/aria/core/scheduler/UploadSchedulers.java
  36. 7
      Aria/src/main/java/com/arialyy/aria/core/upload/BaseUListener.java
  37. 3
      Aria/src/main/java/com/arialyy/aria/core/upload/FtpUploadTarget.java
  38. 74
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpFISAdapter.java
  39. 78
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpFileInfoThread.java
  40. 123
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/FtpThreadTask.java
  41. 13
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/SimpleUploadUtil.java
  42. 6
      Aria/src/main/java/com/arialyy/aria/core/upload/uploader/Uploader.java
  43. 2
      Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java
  44. 13
      Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
  45. 136
      Aria/src/main/java/com/arialyy/aria/util/NetUtils.java
  46. 2
      AriaFtpPlug/bintray-release.gradle
  47. 55
      AriaFtpPlug/src/main/java/org/apache/commons/net/DatagramSocketClient.java
  48. 6
      AriaFtpPlug/src/main/java/org/apache/commons/net/DatagramSocketFactory.java
  49. 17
      AriaFtpPlug/src/main/java/org/apache/commons/net/DefaultDatagramSocketFactory.java
  50. 66
      AriaFtpPlug/src/main/java/org/apache/commons/net/DefaultSocketFactory.java
  51. 10
      AriaFtpPlug/src/main/java/org/apache/commons/net/MalformedServerReplyException.java
  52. 48
      AriaFtpPlug/src/main/java/org/apache/commons/net/PrintCommandListener.java
  53. 27
      AriaFtpPlug/src/main/java/org/apache/commons/net/ProtocolCommandEvent.java
  54. 5
      AriaFtpPlug/src/main/java/org/apache/commons/net/ProtocolCommandListener.java
  55. 34
      AriaFtpPlug/src/main/java/org/apache/commons/net/ProtocolCommandSupport.java
  56. 180
      AriaFtpPlug/src/main/java/org/apache/commons/net/SocketClient.java
  57. 1
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/Configurable.java
  58. 347
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTP.java
  59. 1084
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPClient.java
  60. 82
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPClientConfig.java
  61. 47
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPCmd.java
  62. 33
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPCommand.java
  63. 11
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPConnectionClosedException.java
  64. 123
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPFile.java
  65. 9
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPFileEntryParser.java
  66. 19
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPFileEntryParserImpl.java
  67. 1
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPFileFilter.java
  68. 11
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPFileFilters.java
  69. 34
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPHTTPClient.java
  70. 52
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPListParseEngine.java
  71. 28
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPReply.java
  72. 228
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPSClient.java
  73. 6
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPSCommand.java
  74. 14
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPSServerSocketFactory.java
  75. 58
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPSSocketFactory.java
  76. 23
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/FTPSTrustManager.java
  77. 33
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/OnFtpInputStreamListener.java
  78. 26
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/CompositeFileEntryParser.java
  79. 28
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/ConfigurableFTPFileEntryParserImpl.java
  80. 129
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/DefaultFTPFileEntryParserFactory.java
  81. 67
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/EnterpriseUnixFTPEntryParser.java
  82. 19
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/FTPFileEntryParserFactory.java
  83. 3
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/FTPTimestampParser.java
  84. 62
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java
  85. 72
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/MLSxEntryParser.java
  86. 49
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/MVSFTPEntryParser.java
  87. 118
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/MacOsPeterFTPEntryParser.java
  88. 79
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/NTFTPEntryParser.java
  89. 38
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/NetwareFTPEntryParser.java
  90. 57
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/OS2FTPEntryParser.java
  91. 139
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/OS400FTPEntryParser.java
  92. 4
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/ParserInitializationException.java
  93. 28
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/RegexFTPFileEntryParserImpl.java
  94. 144
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/UnixFTPEntryParser.java
  95. 113
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/VMSFTPEntryParser.java
  96. 52
      AriaFtpPlug/src/main/java/org/apache/commons/net/ftp/parser/VMSVersioningFTPEntryParser.java
  97. 18
      AriaFtpPlug/src/main/java/org/apache/commons/net/io/CRLFLineReader.java
  98. 39
      AriaFtpPlug/src/main/java/org/apache/commons/net/io/CopyStreamAdapter.java
  99. 40
      AriaFtpPlug/src/main/java/org/apache/commons/net/io/CopyStreamEvent.java
  100. 20
      AriaFtpPlug/src/main/java/org/apache/commons/net/io/CopyStreamException.java
  101. Some files were not shown because too many files have changed in this diff Show More

@ -23,7 +23,8 @@ dependencies {
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1' compile 'com.android.support:appcompat-v7:23.1.1'
compile project(':AriaAnnotations') compile project(':AriaAnnotations')
compile 'com.arialyy.aria:aria-ftp-plug:1.0.0' compile 'com.arialyy.aria:aria-ftp-plug:1.0.3'
// compile project(':AriaFtpPlug') // compile project(':AriaFtpPlug')
} }

@ -31,7 +31,7 @@ public class TaskManager {
private static volatile TaskManager INSTANCE = null; private static volatile TaskManager INSTANCE = null;
private Map<String, AbsTask> map = new ConcurrentHashMap<>(); private Map<String, AbsTask> map = new ConcurrentHashMap<>();
public TaskManager getInstance() { public static TaskManager getInstance() {
if (INSTANCE == null) { if (INSTANCE == null) {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
INSTANCE = new TaskManager(); INSTANCE = new TaskManager();

@ -16,10 +16,13 @@
package com.arialyy.aria.core.command.normal; package com.arialyy.aria.core.command.normal;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadTask; import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.inf.AbsNormalTask; import com.arialyy.aria.core.inf.AbsNormalTask;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.queue.DownloadTaskQueue; import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.util.NetUtils;
/** /**
* Created by lyy on 2017/6/2. * Created by lyy on 2017/6/2.
@ -43,6 +46,10 @@ final class HighestPriorityCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T>
@Override public void executeCmd() { @Override public void executeCmd() {
if (!canExeCmd) return; if (!canExeCmd) return;
if (!NetUtils.isConnected(AriaManager.APP)){
Log.w(TAG, "启动任务失败,网络未连接");
return;
}
DownloadTask task = (DownloadTask) getTask(); DownloadTask task = (DownloadTask) getTask();
if (task == null) { if (task == null) {
task = (DownloadTask) createTask(); task = (DownloadTask) createTask();

@ -28,39 +28,39 @@ public class NormalCmdFactory extends AbsCmdFactory<AbsTaskEntity, AbsNormalCmd>
/** /**
* 创建任务 * 创建任务
*/ */
public static final int TASK_CREATE = 0x122; public static final int TASK_CREATE = 0xb1;
/** /**
* 启动任务 * 启动任务
*/ */
public static final int TASK_START = 0x123; public static final int TASK_START = 0xb2;
/** /**
* 恢复任务 * 恢复任务
*/ */
public static final int TASK_RESUME = 0x127; public static final int TASK_RESUME = 0xb3;
/** /**
* 取消任务 * 取消任务
*/ */
public static final int TASK_CANCEL = 0x124; public static final int TASK_CANCEL = 0xb4;
/** /**
* 停止任务 * 停止任务
*/ */
public static final int TASK_STOP = 0x125; public static final int TASK_STOP = 0xb5;
/** /**
* 设置任务为最高优先级 * 设置任务为最高优先级
*/ */
public static final int TASK_HIGHEST_PRIORITY = 0x128; public static final int TASK_HIGHEST_PRIORITY = 0xb6;
/** /**
* 停止所有任务 * 停止所有任务
*/ */
public static final int TASK_STOP_ALL = 0x129; public static final int TASK_STOP_ALL = 0xb7;
/** /**
* 恢复所有停止的任务 * 恢复所有停止的任务
*/ */
public static final int TASK_RESUME_ALL = 0x130; public static final int TASK_RESUME_ALL = 0xb8;
/** /**
* 删除所有任务 * 删除所有任务
*/ */
public static final int TASK_CANCEL_ALL = 0x131; public static final int TASK_CANCEL_ALL = 0xb9;
private static volatile NormalCmdFactory INSTANCE = null; private static volatile NormalCmdFactory INSTANCE = null;
private NormalCmdFactory() { private NormalCmdFactory() {

@ -1,5 +1,7 @@
package com.arialyy.aria.core.command.normal; package com.arialyy.aria.core.command.normal;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity; import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
@ -9,6 +11,7 @@ import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.core.queue.UploadTaskQueue; import com.arialyy.aria.core.queue.UploadTaskQueue;
import com.arialyy.aria.core.upload.UploadTaskEntity; import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.NetUtils;
import java.util.List; import java.util.List;
/** /**
@ -26,6 +29,10 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
} }
@Override public void executeCmd() { @Override public void executeCmd() {
if (!NetUtils.isConnected(AriaManager.APP)) {
Log.w(TAG, "恢复任务失败,网络未连接");
return;
}
if (isDownloadCmd) { if (isDownloadCmd) {
resumeDownload(); resumeDownload();
} else { } else {
@ -41,21 +48,25 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
DbEntity.findDatas(DownloadTaskEntity.class, "isGroupTask=?", "false"); DbEntity.findDatas(DownloadTaskEntity.class, "isGroupTask=?", "false");
if (dTaskEntity != null && !dTaskEntity.isEmpty()) { if (dTaskEntity != null && !dTaskEntity.isEmpty()) {
for (DownloadTaskEntity te : dTaskEntity) { for (DownloadTaskEntity te : dTaskEntity) {
if (te == null || te.getEntity() == null) continue;
int state = te.getState(); int state = te.getState();
if (state == IEntity.STATE_COMPLETE || state == IEntity.STATE_FAIL) continue; if (state == IEntity.STATE_STOP || state == IEntity.STATE_OTHER) {
resumeEntity(te); resumeEntity(te);
} }
} }
}
List<DownloadGroupTaskEntity> groupTask = DbEntity.findAllData(DownloadGroupTaskEntity.class); List<DownloadGroupTaskEntity> groupTask = DbEntity.findAllData(DownloadGroupTaskEntity.class);
if (groupTask != null && !groupTask.isEmpty()) { if (groupTask != null && !groupTask.isEmpty()) {
for (DownloadGroupTaskEntity te : groupTask) { for (DownloadGroupTaskEntity te : groupTask) {
if (te == null || te.getEntity() == null) continue;
int state = te.getState(); int state = te.getState();
if (state == IEntity.STATE_COMPLETE || state == IEntity.STATE_FAIL) continue; if (state == IEntity.STATE_STOP || state == IEntity.STATE_OTHER) {
resumeEntity(te); resumeEntity(te);
} }
} }
} }
}
/** /**
* 恢复上传包括普通任务和任务组 * 恢复上传包括普通任务和任务组
@ -65,12 +76,14 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
DbEntity.findDatas(UploadTaskEntity.class, "isGroupTask=?", "false"); DbEntity.findDatas(UploadTaskEntity.class, "isGroupTask=?", "false");
if (dTaskEntity != null && !dTaskEntity.isEmpty()) { if (dTaskEntity != null && !dTaskEntity.isEmpty()) {
for (UploadTaskEntity te : dTaskEntity) { for (UploadTaskEntity te : dTaskEntity) {
if (te == null || te.getEntity() == null) continue;
int state = te.getState(); int state = te.getState();
if (state == IEntity.STATE_COMPLETE || state == IEntity.STATE_FAIL) continue; if (state == IEntity.STATE_STOP || state == IEntity.STATE_OTHER) {
resumeEntity(te); resumeEntity(te);
} }
} }
} }
}
/** /**
* 恢复实体任务 * 恢复实体任务

@ -17,11 +17,13 @@
package com.arialyy.aria.core.command.normal; package com.arialyy.aria.core.command.normal;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.QueueMod; import com.arialyy.aria.core.common.QueueMod;
import com.arialyy.aria.core.inf.AbsTask; import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.util.NetUtils;
/** /**
* Created by lyy on 2016/8/22. * Created by lyy on 2016/8/22.
@ -36,6 +38,10 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
@Override public void executeCmd() { @Override public void executeCmd() {
if (!canExeCmd) return; if (!canExeCmd) return;
if (!NetUtils.isConnected(AriaManager.APP)) {
Log.w(TAG, "启动任务失败,网络未连接");
return;
}
String mod; String mod;
int maxTaskNum; int maxTaskNum;
AriaManager manager = AriaManager.getInstance(AriaManager.APP); AriaManager manager = AriaManager.getInstance(AriaManager.APP);
@ -64,7 +70,6 @@ class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
} }
} }
} else { } else {
// 任务不存在时,根据配置不同,对任务执行操作
if (!task.isRunning()) { if (!task.isRunning()) {
startTask(); startTask();
} }

@ -85,6 +85,9 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
} }
@Override public void run() { @Override public void run() {
if (mConstance.isRunning) {
return;
}
startFlow(); startFlow();
} }
@ -92,12 +95,11 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
* 开始下载流程 * 开始下载流程
*/ */
private void startFlow() { private void startFlow() {
mConstance.resetState();
checkTask(); checkTask();
if (mListener instanceof IDownloadListener) { if (mListener instanceof IDownloadListener) {
((IDownloadListener) mListener).onPostPre(mEntity.getFileSize()); ((IDownloadListener) mListener).onPostPre(mEntity.getFileSize());
} }
mConstance.cleanState();
mConstance.isRunning = true;
if (!mTaskEntity.isSupportBP) { if (!mTaskEntity.isSupportBP) {
mThreadNum = 1; mThreadNum = 1;
mConstance.THREAD_NUM = mThreadNum; mConstance.THREAD_NUM = mThreadNum;
@ -125,7 +127,10 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
mTimer = new Timer(true); mTimer = new Timer(true);
mTimer.schedule(new TimerTask() { mTimer.schedule(new TimerTask() {
@Override public void run() { @Override public void run() {
if (mConstance.isComplete() || !mConstance.isRunning) { if (mConstance.isComplete()
|| mConstance.isStop()
|| mConstance.isCancel()
|| !mConstance.isRunning) {
closeTimer(); closeTimer();
} else if (mConstance.CURRENT_LOCATION >= 0) { } else if (mConstance.CURRENT_LOCATION >= 0) {
mListener.onProgress(mConstance.CURRENT_LOCATION); mListener.onProgress(mConstance.CURRENT_LOCATION);
@ -179,9 +184,9 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
@Override public void stop() { @Override public void stop() {
closeTimer(); closeTimer();
if (mConstance.isComplete()) return;
mConstance.isStop = true;
mConstance.isRunning = false; mConstance.isRunning = false;
mConstance.isStop = true;
if (mConstance.isComplete()) return;
if (mFixedThreadPool != null) { if (mFixedThreadPool != null) {
mFixedThreadPool.shutdown(); mFixedThreadPool.shutdown();
} }
@ -393,5 +398,4 @@ public abstract class AbsFileer<ENTITY extends AbsNormalEntity, TASK_ENTITY exte
* 选择单任务线程的类型 * 选择单任务线程的类型
*/ */
protected abstract AbsThreadTask selectThreadTask(SubThreadConfig<TASK_ENTITY> config); protected abstract AbsThreadTask selectThreadTask(SubThreadConfig<TASK_ENTITY> config);
} }

@ -0,0 +1,198 @@
/*
* 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.common;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.upload.UploadEntity;
import java.io.IOException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
/**
* Created by Aria.Lao on 2017/7/25.
* 获取ftp文件夹信息
*/
public abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements Runnable {
private final String TAG = "AbsFtpInfoThread";
protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity;
private int mConnectTimeOut;
protected OnFileInfoCallback mCallback;
protected long mSize = 0;
protected String mServerIp, mPort;
protected String charSet = "UTF-8";
private boolean isUpload = false;
public AbsFtpInfoThread(TASK_ENTITY taskEntity, OnFileInfoCallback callback) {
mTaskEntity = taskEntity;
mEntity = taskEntity.getEntity();
mConnectTimeOut =
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getConnectTimeOut();
mCallback = callback;
if (mEntity instanceof UploadEntity) {
isUpload = true;
}
}
/**
* 设置请求的远程文件路径
*
* @return 远程文件路径
*/
protected abstract String setRemotePath();
@Override public void run() {
FTPClient client = null;
try {
client = createFtpClient();
if (client == null) return;
String remotePath =
new String(setRemotePath().getBytes(charSet), AbsFtpThreadTask.SERVER_CHARSET);
FTPFile[] files = client.listFiles(remotePath);
mSize = getFileSize(files, client, remotePath);
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
if (isUpload) {
//服务器上没有该文件路径,表示该任务为新的上传任务
mTaskEntity.isNewTask = true;
} else {
client.disconnect();
failDownload("获取文件信息错误,错误码为:" + reply);
return;
}
}
mTaskEntity.code = reply;
if (mSize != 0 && !isUpload) {
mEntity.setFileSize(mSize);
}
mEntity.update();
mTaskEntity.update();
onPreComplete(reply);
} catch (IOException e) {
failDownload(e.getMessage());
} finally {
if (client != null) {
try {
client.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void start() {
new Thread(this).start();
}
protected void onPreComplete(int code) {
}
/**
* 创建FTP客户端
*/
private FTPClient createFtpClient() throws IOException {
String url = "";
if (mEntity instanceof DownloadEntity) {
url = ((DownloadEntity) mEntity).getUrl();
} else if (mEntity instanceof UploadEntity) {
url = ((UploadEntity) mEntity).getUrl();
} else if (mEntity instanceof DownloadGroupEntity) {
url = mEntity.getKey();
} else {
failDownload("未知实体");
Log.e(TAG, "未知实体");
return null;
}
String[] pp = url.split("/")[2].split(":");
mServerIp = pp[0];
mPort = pp[1];
FTPClient client = new FTPClient();
// 连接服务器
client.connect(mServerIp, Integer.parseInt(mPort));
if (!TextUtils.isEmpty(mTaskEntity.account)) {
client.login(mTaskEntity.userName, mTaskEntity.userPw);
} else {
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
failDownload("无法连接到ftp服务器,错误码为:" + reply);
return null;
}
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
charSet = "UTF-8";
if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion(
client.sendCommand("OPTS UTF8", "ON"))) {
charSet = mTaskEntity.charSet;
}
client.setControlEncoding(charSet);
client.setDataTimeout(10 * 1000);
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
client.setControlKeepAliveTimeout(5);
return client;
}
/**
* 遍历FTP服务器上对应文件或文件夹大小
*
* @throws IOException 字符串编码转换错误
*/
private long getFileSize(FTPFile[] files, FTPClient client, String dirName) throws IOException {
long size = 0;
String path = dirName + "/";
for (FTPFile file : files) {
if (file.isFile()) {
size += file.getSize();
handleFile(path + file.getName(), file);
} else {
String remotePath =
new String((path + file.getName()).getBytes(charSet), AbsFtpThreadTask.SERVER_CHARSET);
size += getFileSize(client.listFiles(remotePath), client, path + file.getName());
}
}
return size;
}
/**
* 处理FTP文件信息
*
* @param remotePath ftp服务器文件夹路径
* @param ftpFile ftp服务器上对应的文件
*/
protected void handleFile(String remotePath, FTPFile ftpFile) {
}
private void failDownload(String errorMsg) {
Log.e(TAG, errorMsg);
if (mCallback != null) {
mCallback.onFail(mEntity.getKey(), errorMsg);
}
}
}

@ -0,0 +1,81 @@
/*
* 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.common;
import android.text.TextUtils;
import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEventListener;
import java.io.IOException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
/**
* Created by lyy on 2017/9/26.
* FTP单任务父类
*/
public abstract class AbsFtpThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
extends AbsThreadTask<ENTITY, TASK_ENTITY> {
protected String charSet, serverIp, port;
/**
* FTP 服务器编码
*/
public static String SERVER_CHARSET = "ISO-8859-1";
protected AbsFtpThreadTask(StateConstance constance, IEventListener listener,
SubThreadConfig<TASK_ENTITY> info) {
super(constance, listener, info);
}
/**
* 构建FTP客户端
*/
protected FTPClient createClient() throws IOException {
String url = mEntity.getUrl();
String[] pp = url.split("/")[2].split(":");
serverIp = pp[0];
port = pp[1];
FTPClient client = new FTPClient();
// 连接服务器
client.connect(serverIp, Integer.parseInt(port));
if (!TextUtils.isEmpty(mTaskEntity.account)) {
client.login(mTaskEntity.userName, mTaskEntity.userPw);
} else {
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
fail(STATE.CURRENT_LOCATION, "无法连接到ftp服务器,错误码为:" + reply, null);
return null;
}
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
charSet = "UTF-8";
if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion(
client.sendCommand("OPTS UTF8", "ON"))) {
charSet = mTaskEntity.charSet;
}
client.setControlEncoding(charSet);
client.setDataTimeout(STATE.READ_TIME_OUT);
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
client.setBufferSize(mBufSize);
client.setControlKeepAliveTimeout(5);
//client.setCopyStreamListener();
return client;
}
}

@ -19,12 +19,13 @@ import android.os.Build;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEventListener; import com.arialyy.aria.core.inf.IEventListener;
import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.ErrorHelp; import com.arialyy.aria.util.ErrorHelp;
import com.arialyy.aria.util.NetUtils;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -36,7 +37,7 @@ import java.util.TimerTask;
* Created by lyy on 2017/1/18. * Created by lyy on 2017/1/18.
* 任务线程 * 任务线程
*/ */
public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>> public abstract class AbsThreadTask<ENTITY extends AbsNormalEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements Runnable { implements Runnable {
/** /**
* 线程重试次数 * 线程重试次数
@ -55,10 +56,6 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
protected SubThreadConfig<TASK_ENTITY> mConfig; protected SubThreadConfig<TASK_ENTITY> mConfig;
protected ENTITY mEntity; protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity; protected TASK_ENTITY mTaskEntity;
/**
* FTP 服务器编码
*/
public static String SERVER_CHARSET = "ISO-8859-1";
private int mFailNum = 0; private int mFailNum = 0;
private String mTaskType; private String mTaskType;
private Timer mFailTimer; private Timer mFailTimer;
@ -73,9 +70,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
mConfig = info; mConfig = info;
mTaskEntity = mConfig.TASK_ENTITY; mTaskEntity = mConfig.TASK_ENTITY;
mEntity = mTaskEntity.getEntity(); mEntity = mTaskEntity.getEntity();
if (mConfig.SUPPORT_BP) {
mConfigFPath = info.CONFIG_FILE_PATH; mConfigFPath = info.CONFIG_FILE_PATH;
}
mBufSize = manager.getDownloadConfig().getBuffSize(); mBufSize = manager.getDownloadConfig().getBuffSize();
setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMsxSpeed()); setMaxSpeed(AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMsxSpeed());
mTaskType = getTaskType(); mTaskType = getTaskType();
@ -104,14 +99,15 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
try { try {
if (mConfig.SUPPORT_BP) { if (mConfig.SUPPORT_BP) {
final long currentTemp = mChildCurrentLocation;
STATE.STOP_NUM++; STATE.STOP_NUM++;
Log.d(TAG, "任务【" Log.d(TAG, "任务【"
+ mConfig.TEMP_FILE.getName() + mConfig.TEMP_FILE.getName()
+ "】thread__" + "】thread__"
+ mConfig.THREAD_ID + mConfig.THREAD_ID
+ "__停止, stop location ==> " + "__停止, stop location ==> "
+ mChildCurrentLocation); + currentTemp);
writeConfig(false, mChildCurrentLocation); writeConfig(false, currentTemp);
if (STATE.isStop()) { if (STATE.isStop()) {
Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止"); Log.d(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】已停止");
STATE.isRunning = false; STATE.isRunning = false;
@ -169,12 +165,9 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
/** /**
* 任务失败 * 任务失败
*/ */
protected void fail(long currentLocation, String msg, Exception ex) { protected void fail(final long currentLocation, String msg, Exception ex) {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
try { try {
//STATE.FAIL_NUM++;
//STATE.isRunning = false;
//STATE.isStop = true;
if (ex != null) { if (ex != null) {
Log.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex)); Log.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex));
} else { } else {
@ -182,11 +175,7 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
} }
if (mConfig.SUPPORT_BP) { if (mConfig.SUPPORT_BP) {
writeConfig(false, currentLocation); writeConfig(false, currentLocation);
//if (STATE.isFail()) { retryThis(STATE.THREAD_NUM != 1);
// Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败");
// mListener.onFail(true);
//}
retryThis(true);
} else { } else {
Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败"); Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败");
mListener.onFail(true); mListener.onFail(true);
@ -204,7 +193,11 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
* @param needRetry 是否可以重试 * @param needRetry 是否可以重试
*/ */
private void retryThis(boolean needRetry) { private void retryThis(boolean needRetry) {
if (mFailNum < RETRY_NUM && needRetry) { if (!NetUtils.isConnected(AriaManager.APP)) {
Log.w(TAG,
"任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__重试失败,网络未连接");
}
if (mFailNum < RETRY_NUM && needRetry && NetUtils.isConnected(AriaManager.APP)) {
if (mFailTimer != null) { if (mFailTimer != null) {
mFailTimer.purge(); mFailTimer.purge();
mFailTimer.cancel(); mFailTimer.cancel();
@ -215,23 +208,26 @@ public abstract class AbsThreadTask<ENTITY extends AbsEntity, TASK_ENTITY extend
mFailNum++; mFailNum++;
Log.w(TAG, Log.w(TAG,
"任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__正在重试"); "任务【" + mConfig.TEMP_FILE.getName() + "】thread__" + mConfig.THREAD_ID + "__正在重试");
mConfig.START_LOCATION = mChildCurrentLocation; final long retryLocation = mChildCurrentLocation;
mConfig.START_LOCATION = retryLocation;
AbsThreadTask.this.run(); AbsThreadTask.this.run();
} }
}, RETRY_INTERVAL); }, RETRY_INTERVAL);
} else { } else {
STATE.FAIL_NUM++; STATE.FAIL_NUM++;
if (STATE.isFail()) {
STATE.isRunning = false; STATE.isRunning = false;
STATE.isStop = true; STATE.isStop = true;
Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败"); Log.e(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】执行失败");
mListener.onFail(true); mListener.onFail(true);
} }
} }
}
/** /**
* 将记录写入到配置文件 * 将记录写入到配置文件
*/ */
protected void writeConfig(boolean isComplete, long record) throws IOException { protected void writeConfig(boolean isComplete, final long record) throws IOException {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
String key = null, value = null; String key = null, value = null;
if (0 < record && record < mConfig.END_LOCATION) { if (0 < record && record < mConfig.END_LOCATION) {

@ -1,6 +1,6 @@
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.common;
interface OnFileInfoCallback { public interface OnFileInfoCallback {
/** /**
* 处理完成 * 处理完成
* *

@ -35,7 +35,7 @@ public class StateConstance {
public StateConstance() { public StateConstance() {
} }
public void cleanState() { public void resetState() {
isCancel = false; isCancel = false;
isStop = false; isStop = false;
isRunning = true; isRunning = true;
@ -56,7 +56,7 @@ public class StateConstance {
* 所有子线程是否都已经下载失败 * 所有子线程是否都已经下载失败
*/ */
public boolean isFail() { public boolean isFail() {
return FAIL_NUM == THREAD_NUM; return FAIL_NUM + COMPLETE_THREAD_NUM >= THREAD_NUM;
} }
/** /**

@ -31,12 +31,14 @@ import java.lang.ref.WeakReference;
class BaseDListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>> class BaseDListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>>
implements IDownloadListener { implements IDownloadListener {
protected WeakReference<Handler> outHandler; protected WeakReference<Handler> outHandler;
private int RUN_SAVE_INTERVAL = 5 * 1000; //5s保存一次下载中的进度
private long mLastLen = 0; //上一次发送长度 private long mLastLen = 0; //上一次发送长度
private boolean isFirst = true; private boolean isFirst = true;
protected ENTITY mEntity; protected ENTITY mEntity;
protected TASK mTask; protected TASK mTask;
private boolean isConvertSpeed = false; private boolean isConvertSpeed = false;
boolean isWait = false; boolean isWait = false;
private long mLastSaveTime;
BaseDListener(TASK task, Handler outHandler) { BaseDListener(TASK task, Handler outHandler) {
this.outHandler = new WeakReference<>(outHandler); this.outHandler = new WeakReference<>(outHandler);
@ -45,6 +47,7 @@ class BaseDListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>>
final AriaManager manager = AriaManager.getInstance(AriaManager.APP); final AriaManager manager = AriaManager.getInstance(AriaManager.APP);
isConvertSpeed = manager.getDownloadConfig().isConvertSpeed(); isConvertSpeed = manager.getDownloadConfig().isConvertSpeed();
mLastLen = mEntity.getCurrentProgress(); mLastLen = mEntity.getCurrentProgress();
mLastSaveTime = System.currentTimeMillis();
} }
@Override public void onPre() { @Override public void onPre() {
@ -82,6 +85,11 @@ class BaseDListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>>
} }
handleSpeed(speed); handleSpeed(speed);
sendInState2Target(ISchedulers.RUNNING); sendInState2Target(ISchedulers.RUNNING);
if (System.currentTimeMillis() - mLastSaveTime >= RUN_SAVE_INTERVAL){
saveData(IEntity.STATE_RUNNING, currentLocation);
mLastSaveTime = System.currentTimeMillis();
}
mLastLen = currentLocation; mLastLen = currentLocation;
} }

@ -17,6 +17,7 @@ package com.arialyy.aria.core.download;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.util.Log;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.download.downloader.AbsGroupUtil; import com.arialyy.aria.core.download.downloader.AbsGroupUtil;
@ -56,23 +57,23 @@ public class DownloadGroupTask extends AbsGroupTask<DownloadGroupTaskEntity, Dow
} }
@Override public void start() { @Override public void start() {
if (mUtil.isRunning()) {
Log.d(TAG, "任务正在下载");
} else {
mUtil.start(); mUtil.start();
} }
}
@Override public void stop() { @Override public void stop() {
if (!mUtil.isRunning()) { if (!mUtil.isRunning()) {
if (mOutHandler != null) { mListener.onStop(mEntity.getCurrentProgress());
mOutHandler.obtainMessage(ISchedulers.STOP, this).sendToTarget();
}
} }
mUtil.stop(); mUtil.stop();
} }
@Override public void cancel() { @Override public void cancel() {
if (!mUtil.isRunning()) { if (!mUtil.isRunning()) {
if (mOutHandler != null) { mListener.onCancel();
mOutHandler.obtainMessage(ISchedulers.CANCEL, this).sendToTarget();
}
} }
mUtil.cancel(); mUtil.cancel();
} }

@ -128,11 +128,7 @@ public class DownloadTask extends AbsNormalTask<DownloadEntity> {
if (mUtil.isRunning()) { if (mUtil.isRunning()) {
mUtil.stop(); mUtil.stop();
} else { } else {
mEntity.setState(isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP); mListener.onStop(mEntity.getCurrentProgress());
mEntity.update();
if (mOutHandler != null) {
mOutHandler.obtainMessage(ISchedulers.STOP, this).sendToTarget();
}
} }
} }
@ -141,9 +137,7 @@ public class DownloadTask extends AbsNormalTask<DownloadEntity> {
*/ */
@Override public void cancel() { @Override public void cancel() {
if (!mUtil.isRunning()) { if (!mUtil.isRunning()) {
if (mOutHandler != null) { mListener.onCancel();
mOutHandler.obtainMessage(ISchedulers.CANCEL, this).sendToTarget();
}
} }
mUtil.cancel(); mUtil.cancel();
} }

@ -1,155 +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.download.downloader;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.AbsThreadTask;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.util.CommonUtil;
import java.io.IOException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
/**
* Created by Aria.Lao on 2017/7/25.
* 获取ftp文件夹信息
*/
abstract class AbsFtpInfoThread<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity<ENTITY>>
implements Runnable {
private final String TAG = "HttpFileInfoThread";
protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity;
private int mConnectTimeOut;
private OnFileInfoCallback mCallback;
protected long mSize = 0;
AbsFtpInfoThread(TASK_ENTITY taskEntity, OnFileInfoCallback callback) {
mTaskEntity = taskEntity;
mEntity = taskEntity.getEntity();
mConnectTimeOut =
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getConnectTimeOut();
mCallback = callback;
}
@Override public void run() {
FTPClient client = null;
try {
String url = mTaskEntity.getEntity().getKey();
String[] pp = url.split("/")[2].split(":");
String serverIp = pp[0];
int port = Integer.parseInt(pp[1]);
String remotePath = url.substring(url.indexOf(pp[1]) + pp[1].length(), url.length());
client = new FTPClient();
client.connect(serverIp, port);
if (!TextUtils.isEmpty(mTaskEntity.account)) {
client.login(mTaskEntity.userName, mTaskEntity.userPw);
} else {
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
failDownload("无法连接到ftp服务器,错误码为:" + reply);
return;
}
client.setDataTimeout(mConnectTimeOut);
String charSet = "UTF-8";
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion(
client.sendCommand("OPTS UTF8", "ON"))) {
charSet = mTaskEntity.charSet;
}
client.setControlEncoding(charSet);
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
FTPFile[] files =
client.listFiles(new String(remotePath.getBytes(charSet), AbsThreadTask.SERVER_CHARSET));
mSize = getFileSize(files, client, remotePath);
reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
failDownload("获取文件信息错误,错误码为:" + reply);
return;
}
mTaskEntity.code = reply;
onPreComplete();
mEntity.update();
mTaskEntity.update();
mCallback.onComplete(mEntity.getKey(), reply);
} catch (IOException e) {
failDownload(e.getMessage());
} finally {
if (client != null) {
try {
client.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
void start() {
new Thread(this).start();
}
protected void onPreComplete() {
}
/**
* 遍历FTP服务器上对应文件或文件夹大小
*
* @throws IOException
*/
private long getFileSize(FTPFile[] files, FTPClient client, String dirName) throws IOException {
long size = 0;
String path = dirName + "/";
for (FTPFile file : files) {
if (file.isFile()) {
size += file.getSize();
handleFile(path + file.getName(), file);
} else {
size += getFileSize(client.listFiles(
CommonUtil.strCharSetConvert(path + file.getName(), mTaskEntity.charSet)), client,
path + file.getName());
}
}
return size;
}
/**
* 处理FTP文件信息
*
* @param remotePath ftp服务器文件夹路径
* @param ftpFile ftp服务器上对应的文件
*/
void handleFile(String remotePath, FTPFile ftpFile) {
}
private void failDownload(String errorMsg) {
Log.e(TAG, errorMsg);
if (mCallback != null) {
mCallback.onFail(mEntity.getKey(), errorMsg);
}
}
}

@ -25,6 +25,7 @@ import com.arialyy.aria.core.inf.IDownloadListener;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import com.arialyy.aria.util.NetUtils;
import java.io.File; import java.io.File;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -42,23 +43,15 @@ import java.util.concurrent.Executors;
public abstract class AbsGroupUtil implements IUtil { public abstract class AbsGroupUtil implements IUtil {
private final String TAG = "AbsGroupUtil"; private final String TAG = "AbsGroupUtil";
/** /**
* 任务组所有任务总大小 * 任务组所有任务总长度
*/ */
long mTotalSize = 0; long mTotalLen = 0;
long mCurrentLocation = 0; long mCurrentLocation = 0;
private ExecutorService mExePool; private ExecutorService mExePool;
protected IDownloadGroupListener mListener; protected IDownloadGroupListener mListener;
protected DownloadGroupTaskEntity mTaskEntity; protected DownloadGroupTaskEntity mTaskEntity;
private boolean isRunning = false; private boolean isRunning = false;
private Timer mTimer; private Timer mTimer;
/**
* 初始化完成的任务书数
*/
int mInitNum = 0;
/**
* 初始化失败的任务数
*/
int mInitFailNum = 0;
/** /**
* 保存所有没有下载完成的任务key为下载地址 * 保存所有没有下载完成的任务key为下载地址
*/ */
@ -78,18 +71,26 @@ public abstract class AbsGroupUtil implements IUtil {
* 该任务组对应的所有任务 * 该任务组对应的所有任务
*/ */
private Map<String, DownloadTaskEntity> mTasksMap = new HashMap<>(); private Map<String, DownloadTaskEntity> mTasksMap = new HashMap<>();
/**
* 是否需要读取文件长度{@code true}需要
*/
boolean isNeedLoadFileSize = true;
//已经完成的任务数 //已经完成的任务数
private int mCompleteNum = 0; private int mCompleteNum = 0;
//失败的任务数 //失败的任务数
private int mFailNum = 0; private int mFailNum = 0;
//停止的任务数 //停止的任务数
private int mStopNum = 0; private int mStopNum = 0;
//实际的下载任务数 //实际的下载任务数
int mActualTaskNum = 0; int mActualTaskNum = 0;
/** //初始化完成的任务数
* 是否需要读取文件长度{@code true}需要 int mInitNum = 0;
*/ // 初始化失败的任务数
boolean isNeedLoadFileSize = true; int mInitFailNum = 0;
//任务组大小
int mGroupSize = 0;
AbsGroupUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity taskEntity) { AbsGroupUtil(IDownloadGroupListener listener, DownloadGroupTaskEntity taskEntity) {
mListener = listener; mListener = listener;
@ -104,14 +105,13 @@ public abstract class AbsGroupUtil implements IUtil {
mTasksMap.put(te.getEntity().getUrl(), te); mTasksMap.put(te.getEntity().getUrl(), te);
} }
} }
mTotalSize = taskEntity.getEntity().getFileSize(); mGroupSize = mTaskEntity.entity.getSubTask().size();
isNeedLoadFileSize = mTotalSize <= 1; mTotalLen = taskEntity.getEntity().getFileSize();
isNeedLoadFileSize = mTotalLen <= 1;
for (DownloadEntity entity : mTaskEntity.entity.getSubTask()) { for (DownloadEntity entity : mTaskEntity.entity.getSubTask()) {
File file = new File(entity.getDownloadPath()); File file = new File(entity.getDownloadPath());
if (entity.getState() == IEntity.STATE_COMPLETE && file.exists()) { if (entity.getState() == IEntity.STATE_COMPLETE && file.exists()) {
mCompleteNum++; mCompleteNum++;
mInitNum++;
mStopNum++;
mCurrentLocation += entity.getFileSize(); mCurrentLocation += entity.getFileSize();
} else { } else {
mExeMap.put(entity.getUrl(), createChildDownloadTask(entity)); mExeMap.put(entity.getUrl(), createChildDownloadTask(entity));
@ -119,7 +119,7 @@ public abstract class AbsGroupUtil implements IUtil {
mActualTaskNum++; mActualTaskNum++;
} }
if (isNeedLoadFileSize) { if (isNeedLoadFileSize) {
mTotalSize += entity.getFileSize(); mTotalLen += entity.getFileSize();
} }
} }
updateFileSize(); updateFileSize();
@ -127,7 +127,7 @@ public abstract class AbsGroupUtil implements IUtil {
void updateFileSize() { void updateFileSize() {
if (isNeedLoadFileSize) { if (isNeedLoadFileSize) {
mTaskEntity.getEntity().setFileSize(mTotalSize); mTaskEntity.getEntity().setFileSize(mTotalLen);
mTaskEntity.getEntity().update(); mTaskEntity.getEntity().update();
} }
} }
@ -211,7 +211,7 @@ public abstract class AbsGroupUtil implements IUtil {
} }
@Override public long getFileSize() { @Override public long getFileSize() {
return mTotalSize; return mTotalLen;
} }
@Override public long getCurrentLocation() { @Override public long getCurrentLocation() {
@ -271,7 +271,6 @@ public abstract class AbsGroupUtil implements IUtil {
@Override public void stop() { @Override public void stop() {
closeTimer(false); closeTimer(false);
mListener.onStop(mCurrentLocation);
onStop(); onStop();
if (!mExePool.isShutdown()) { if (!mExePool.isShutdown()) {
mExePool.shutdown(); mExePool.shutdown();
@ -324,7 +323,7 @@ public abstract class AbsGroupUtil implements IUtil {
*/ */
void startRunningFlow() { void startRunningFlow() {
closeTimer(true); closeTimer(true);
mListener.onPostPre(mTotalSize); mListener.onPostPre(mTotalLen);
mListener.onStart(mCurrentLocation); mListener.onStart(mCurrentLocation);
startTimer(); startTimer();
} }
@ -405,14 +404,16 @@ public abstract class AbsGroupUtil implements IUtil {
DownloadTaskEntity taskEntity; DownloadTaskEntity taskEntity;
DownloadEntity entity; DownloadEntity entity;
private int RUN_SAVE_INTERVAL = 5 * 1000; //5s保存一次下载中的进度
private long mLastSaveTime;
long lastLen = 0; long lastLen = 0;
ChildDownloadListener(DownloadTaskEntity entity) { ChildDownloadListener(DownloadTaskEntity entity) {
this.taskEntity = entity; this.taskEntity = entity;
this.entity = taskEntity.getEntity(); this.entity = taskEntity.getEntity();
lastLen = this.entity.getCurrentProgress();
this.entity.setFailNum(0); this.entity.setFailNum(0);
lastLen = this.entity.getCurrentProgress();
mLastSaveTime = System.currentTimeMillis();
} }
@Override public void onPre() { @Override public void onPre() {
@ -444,6 +445,10 @@ public abstract class AbsGroupUtil implements IUtil {
entity.setCurrentProgress(currentLocation); entity.setCurrentProgress(currentLocation);
handleSpeed(speed); handleSpeed(speed);
mListener.onSubRunning(entity); mListener.onSubRunning(entity);
if (System.currentTimeMillis() - mLastSaveTime >= RUN_SAVE_INTERVAL) {
saveData(IEntity.STATE_RUNNING, currentLocation);
mLastSaveTime = System.currentTimeMillis();
}
lastLen = currentLocation; lastLen = currentLocation;
} }
@ -451,12 +456,14 @@ public abstract class AbsGroupUtil implements IUtil {
saveData(IEntity.STATE_STOP, stopLocation); saveData(IEntity.STATE_STOP, stopLocation);
handleSpeed(0); handleSpeed(0);
mListener.onSubStop(entity); mListener.onSubStop(entity);
synchronized (AbsGroupUtil.class) {
mStopNum++; mStopNum++;
if (mStopNum + mCompleteNum >= mInitNum) { if (mStopNum + mCompleteNum + mInitFailNum + mFailNum >= mGroupSize) {
closeTimer(false); closeTimer(false);
mListener.onStop(mCurrentLocation); mListener.onStop(mCurrentLocation);
} }
} }
}
@Override public void onCancel() { @Override public void onCancel() {
saveData(IEntity.STATE_CANCEL, -1); saveData(IEntity.STATE_CANCEL, -1);
@ -466,16 +473,19 @@ public abstract class AbsGroupUtil implements IUtil {
@Override public void onComplete() { @Override public void onComplete() {
saveData(IEntity.STATE_COMPLETE, entity.getFileSize()); saveData(IEntity.STATE_COMPLETE, entity.getFileSize());
mCompleteNum++;
handleSpeed(0); handleSpeed(0);
mListener.onSubComplete(entity); mListener.onSubComplete(entity);
synchronized (AbsGroupUtil.class) {
mCompleteNum++;
//如果子任务完成的数量和总任务数一致,表示任务组任务已经完成 //如果子任务完成的数量和总任务数一致,表示任务组任务已经完成
if (mCompleteNum >= mTaskEntity.getEntity().getSubTask().size()) { if (mCompleteNum >= mGroupSize) {
closeTimer(false); closeTimer(false);
mListener.onComplete(); mListener.onComplete();
} else if (mCompleteNum + mFailNum >= mActualTaskNum) { } else if (mStopNum + mCompleteNum + mInitFailNum + mFailNum >= mGroupSize) {
//如果子任务完成数量加上失败的数量和总任务数一致,则任务组停止下载 //如果子任务完成数量加上失败的数量和总任务数一致,则任务组停止下载
closeTimer(false); closeTimer(false);
mListener.onStop(mCurrentLocation);
}
} }
} }
@ -491,7 +501,8 @@ public abstract class AbsGroupUtil implements IUtil {
*/ */
private void reTry(boolean needRetry) { private void reTry(boolean needRetry) {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
if (entity.getFailNum() < 5 && isRunning && needRetry) { if (entity.getFailNum() < 5 && isRunning && needRetry && NetUtils.isConnected(
AriaManager.APP)) {
reStartTask(); reStartTask();
} else { } else {
mFailNum++; mFailNum++;

@ -17,6 +17,7 @@ package com.arialyy.aria.core.download.downloader;
import android.util.SparseArray; import android.util.SparseArray;
import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity; import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
@ -73,7 +74,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
} }
} }
if (i != 0 && i == mExeMap.size()) startRunningFlow(); if (i != 0 && i == mExeMap.size()) startRunningFlow();
if (mCurrentLocation == mTotalSize) { if (mCurrentLocation == mTotalLen) {
mListener.onComplete(); mListener.onComplete();
} }
} }
@ -92,7 +93,7 @@ public class DownloadGroupUtil extends AbsGroupUtil implements IUtil {
DownloadTaskEntity te = mExeMap.get(url); DownloadTaskEntity te = mExeMap.get(url);
if (te != null) { if (te != null) {
if (isNeedLoadFileSize) { if (isNeedLoadFileSize) {
mTotalSize += te.getEntity().getFileSize(); mTotalLen += te.getEntity().getFileSize();
} }
createChildDownload(te); createChildDownload(te);
} }

@ -16,7 +16,6 @@
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.AbsFileer; import com.arialyy.aria.core.common.AbsFileer;
import com.arialyy.aria.core.common.AbsThreadTask; import com.arialyy.aria.core.common.AbsThreadTask;
import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.common.SubThreadConfig;
@ -43,10 +42,7 @@ class Downloader extends AbsFileer<DownloadEntity, DownloadTaskEntity> {
} }
@Override protected void checkTask() { @Override protected void checkTask() {
mConfigFile = new File(mContext.getFilesDir().getPath() mConfigFile = new File(CommonUtil.getFileConfigPath(true, mEntity.getFileName()));
+ AriaManager.DOWNLOAD_TEMP_DIR
+ mEntity.getFileName()
+ ".properties");
mTempFile = new File(mEntity.getDownloadPath()); mTempFile = new File(mEntity.getDownloadPath());
if (!mTaskEntity.isSupportBP) { if (!mTaskEntity.isSupportBP) {
isNewTask = true; isNewTask = true;

@ -15,6 +15,7 @@
*/ */
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity; import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
@ -42,6 +43,8 @@ public class FtpDirDownloadUtil extends AbsGroupUtil {
mExeMap.put(entity.getUrl(), createChildDownloadTask(entity)); mExeMap.put(entity.getUrl(), createChildDownloadTask(entity));
} }
mActualTaskNum = mTaskEntity.entity.getSubTask().size(); mActualTaskNum = mTaskEntity.entity.getSubTask().size();
mGroupSize = mActualTaskNum;
mTotalLen = mTaskEntity.entity.getFileSize();
startDownload(); startDownload();
} }
} }

@ -15,6 +15,8 @@
*/ */
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.common.AbsFtpInfoThread;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity; import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity; import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
@ -33,14 +35,20 @@ class FtpDirInfoThread extends AbsFtpInfoThread<DownloadGroupEntity, DownloadGro
super(taskEntity, callback); super(taskEntity, callback);
} }
@Override void handleFile(String remotePath, FTPFile ftpFile) { @Override protected String setRemotePath() {
String url = mEntity.getKey();
return url.substring(url.indexOf(mPort) + mPort.length(), url.length());
}
@Override protected void handleFile(String remotePath, FTPFile ftpFile) {
super.handleFile(remotePath, ftpFile); super.handleFile(remotePath, ftpFile);
addEntity(remotePath, ftpFile); addEntity(remotePath, ftpFile);
} }
@Override protected void onPreComplete() { @Override protected void onPreComplete(int code) {
super.onPreComplete(); super.onPreComplete(code);
mEntity.setFileSize(mSize); mEntity.setFileSize(mSize);
mCallback.onComplete(mEntity.getKey(), code);
} }
private void addEntity(String remotePath, FTPFile ftpFile) { private void addEntity(String remotePath, FTPFile ftpFile) {

@ -15,6 +15,8 @@
*/ */
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.common.AbsFtpInfoThread;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
@ -28,11 +30,17 @@ class FtpFileInfoThread extends AbsFtpInfoThread<DownloadEntity, DownloadTaskEnt
super(taskEntity, callback); super(taskEntity, callback);
} }
@Override protected void onPreComplete() { @Override protected String setRemotePath() {
super.onPreComplete(); String url = mEntity.getUrl();
return url.substring(url.indexOf(mPort) + mPort.length(), url.length());
}
@Override protected void onPreComplete(int code) {
super.onPreComplete(code);
if (mSize != mTaskEntity.getEntity().getFileSize()) { if (mSize != mTaskEntity.getEntity().getFileSize()) {
mTaskEntity.isNewTask = true; mTaskEntity.isNewTask = true;
} }
mEntity.setFileSize(mSize); mEntity.setFileSize(mSize);
mCallback.onComplete(mEntity.getUrl(), code);
} }
} }

@ -15,9 +15,8 @@
*/ */
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.common.AbsThreadTask; import com.arialyy.aria.core.common.AbsFtpThreadTask;
import com.arialyy.aria.core.common.StateConstance; import com.arialyy.aria.core.common.StateConstance;
import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
@ -27,7 +26,6 @@ import com.arialyy.aria.util.BufferedRandomAccessFile;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply; import org.apache.commons.net.ftp.FTPReply;
@ -35,7 +33,7 @@ import org.apache.commons.net.ftp.FTPReply;
* Created by Aria.Lao on 2017/7/24. * Created by Aria.Lao on 2017/7/24.
* Ftp下载任务 * Ftp下载任务
*/ */
class FtpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEntity> { class FtpThreadTask extends AbsFtpThreadTask<DownloadEntity, DownloadTaskEntity> {
private final String TAG = "FtpThreadTask"; private final String TAG = "FtpThreadTask";
FtpThreadTask(StateConstance constance, IDownloadListener listener, FtpThreadTask(StateConstance constance, IDownloadListener listener,
@ -57,40 +55,16 @@ class FtpThreadTask extends AbsThreadTask<DownloadEntity, DownloadTaskEntity> {
+ ",结束位置:" + ",结束位置:"
+ mConfig.END_LOCATION + mConfig.END_LOCATION
+ "】"); + "】");
client = createClient();
if (client == null) return;
String url = mEntity.getUrl(); String url = mEntity.getUrl();
String[] pp = url.split("/")[2].split(":"); String remotePath = new String(
String serverIp = pp[0]; url.substring(url.indexOf(port) + port.length(), url.length()).getBytes(charSet),
int port = Integer.parseInt(pp[1]); SERVER_CHARSET);
String remotePath = url.substring(url.indexOf(pp[1]) + pp[1].length(), url.length());
client = new FTPClient();
client.connect(serverIp, port);
if (!TextUtils.isEmpty(mTaskEntity.account)) {
client.login(mTaskEntity.userName, mTaskEntity.userPw);
} else {
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account);
}
int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
client.disconnect();
fail(STATE.CURRENT_LOCATION, "无法连接到ftp服务器,错误码为:" + reply, null);
return;
}
String charSet = "UTF-8";
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion(
client.sendCommand("OPTS UTF8", "ON"))) {
charSet = mTaskEntity.charSet;
}
client.setControlEncoding(charSet);
client.setDataTimeout(STATE.READ_TIME_OUT);
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
client.setRestartOffset(mConfig.START_LOCATION); client.setRestartOffset(mConfig.START_LOCATION);
client.allocate(mBufSize); is = client.retrieveFileStream(remotePath);
is = client.retrieveFileStream(
new String(remotePath.getBytes(charSet), SERVER_CHARSET));
//发送第二次指令时,还需要再做一次判断 //发送第二次指令时,还需要再做一次判断
reply = client.getReplyCode(); int reply = client.getReplyCode();
if (!FTPReply.isPositivePreliminary(reply)) { if (!FTPReply.isPositivePreliminary(reply)) {
client.disconnect(); client.disconnect();
fail(mChildCurrentLocation, "获取文件信息错误,错误码为:" + reply, null); fail(mChildCurrentLocation, "获取文件信息错误,错误码为:" + reply, null);

@ -18,6 +18,7 @@ package com.arialyy.aria.core.download.downloader;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;

@ -17,6 +17,7 @@
package com.arialyy.aria.core.download.downloader; package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IDownloadListener; import com.arialyy.aria.core.inf.IDownloadListener;

@ -19,6 +19,8 @@ import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.orm.Ignore; import com.arialyy.aria.orm.Ignore;
import java.util.LinkedList;
import java.util.List;
/** /**
* Created by AriaL on 2017/6/29. * Created by AriaL on 2017/6/29.

@ -19,10 +19,13 @@ import android.support.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.ICmd;
import com.arialyy.aria.core.command.normal.CancelCmd; import com.arialyy.aria.core.command.normal.CancelCmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory; import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.common.RequestEnum; import com.arialyy.aria.core.common.RequestEnum;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -199,6 +202,16 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
.exe(); .exe();
} }
/**
* 重试下载
*/
public void reTry() {
List<ICmd> cmds = new ArrayList<>();
cmds.add(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP));
cmds.add(CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START));
AriaManager.getInstance(AriaManager.APP).setCmds(cmds).exe();
}
/** /**
* 删除任务 * 删除任务
* *
@ -206,8 +219,8 @@ public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEnti
* {@code false}如果任务已经完成只删除任务数据库记录 * {@code false}如果任务已经完成只删除任务数据库记录
*/ */
public void cancel(boolean removeFile) { public void cancel(boolean removeFile) {
CancelCmd cancelCmd = CancelCmd cancelCmd = (CancelCmd) CommonUtil.createNormalCmd(mTargetName, mTaskEntity,
(CancelCmd) CommonUtil.createNormalCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CANCEL); NormalCmdFactory.TASK_CANCEL);
cancelCmd.removeFile = removeFile; cancelCmd.removeFile = removeFile;
AriaManager.getInstance(AriaManager.APP).setCmd(cancelCmd).exe(); AriaManager.getInstance(AriaManager.APP).setCmd(cancelCmd).exe();
} }

@ -17,13 +17,13 @@ package com.arialyy.aria.core.inf;
import android.content.Context; import android.content.Context;
import android.os.Handler; import android.os.Handler;
import com.arialyy.aria.orm.Ignore;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
/** /**
* Created by AriaL on 2017/6/29. * Created by AriaL on 2017/6/29.
*/ */
public abstract class AbsTask<ENTITY extends AbsEntity> implements ITask<ENTITY> { public abstract class AbsTask<ENTITY extends AbsEntity> implements ITask<ENTITY> {
/** /**
* 是否需要重试默认为true * 是否需要重试默认为true
*/ */

@ -21,6 +21,7 @@ import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTask; import com.arialyy.aria.core.upload.UploadTask;
import com.arialyy.aria.core.upload.UploadTaskEntity; import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /**
@ -39,6 +40,7 @@ public abstract class AbsUploadTarget<TARGET extends AbsUploadTarget, ENTITY ext
CheckUtil.checkDownloadUrl(uploadUrl); CheckUtil.checkDownloadUrl(uploadUrl);
if (mEntity.getUrl().equals(uploadUrl)) return (TARGET) this; if (mEntity.getUrl().equals(uploadUrl)) return (TARGET) this;
mEntity.setUrl(uploadUrl); mEntity.setUrl(uploadUrl);
//mEntity.setUrl(CommonUtil.convertUrl(uploadUrl));
mEntity.update(); mEntity.update();
return (TARGET) this; return (TARGET) this;
} }

@ -18,18 +18,13 @@ package com.arialyy.aria.core.queue;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTask; import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.queue.pool.BaseCachePool; import com.arialyy.aria.core.queue.pool.BaseCachePool;
import com.arialyy.aria.core.queue.pool.BaseExecutePool; import com.arialyy.aria.core.queue.pool.BaseExecutePool;
import java.security.Key; import com.arialyy.aria.util.NetUtils;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/** /**
* Created by lyy on 2017/2/23. * Created by lyy on 2017/2/23.
@ -187,7 +182,11 @@ abstract class AbsTaskQueue<TASK extends AbsTask, TASK_ENTITY extends AbsTaskEnt
@Override public void reTryStart(TASK task) { @Override public void reTryStart(TASK task) {
if (task == null) { if (task == null) {
Log.w(TAG, "重试下载失败,task 为null"); Log.w(TAG, "重试失败,task 为null");
return;
}
if (!NetUtils.isConnected(AriaManager.APP)){
Log.w(TAG, "重试失败,网络未连接");
return; return;
} }
if (!task.isRunning()) { if (!task.isRunning()) {

@ -20,9 +20,7 @@ import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.AbsTask; import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.ITask;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -90,6 +88,7 @@ public class BaseExecutePool<TASK extends AbsTask> implements IPool<TASK> {
* @param maxNum 下载数 * @param maxNum 下载数
*/ */
public void setMaxNum(int maxNum) { public void setMaxNum(int maxNum) {
synchronized (AriaManager.LOCK) {
try { try {
ArrayBlockingQueue<TASK> temp = new ArrayBlockingQueue<>(maxNum); ArrayBlockingQueue<TASK> temp = new ArrayBlockingQueue<>(maxNum);
TASK task; TASK task;
@ -102,6 +101,7 @@ public class BaseExecutePool<TASK extends AbsTask> implements IPool<TASK> {
e.printStackTrace(); e.printStackTrace();
} }
} }
}
/** /**
* 添加新任务 * 添加新任务
@ -109,6 +109,7 @@ public class BaseExecutePool<TASK extends AbsTask> implements IPool<TASK> {
* @param newTask 新任务 * @param newTask 新任务
*/ */
boolean putNewTask(TASK newTask) { boolean putNewTask(TASK newTask) {
synchronized (AriaManager.LOCK) {
String url = newTask.getKey(); String url = newTask.getKey();
boolean s = mExecuteQueue.offer(newTask); boolean s = mExecuteQueue.offer(newTask);
Log.w(TAG, "任务添加" + (s ? "成功" : "失败,【" + url + "】")); Log.w(TAG, "任务添加" + (s ? "成功" : "失败,【" + url + "】"));
@ -117,11 +118,13 @@ public class BaseExecutePool<TASK extends AbsTask> implements IPool<TASK> {
} }
return s; return s;
} }
}
/** /**
* 队列满时将移除下载队列中的第一个任务 * 队列满时将移除下载队列中的第一个任务
*/ */
boolean pollFirstTask() { boolean pollFirstTask() {
synchronized (AriaManager.LOCK) {
try { try {
TASK oldTask = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS); TASK oldTask = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
if (oldTask == null) { if (oldTask == null) {
@ -137,6 +140,7 @@ public class BaseExecutePool<TASK extends AbsTask> implements IPool<TASK> {
} }
return true; return true;
} }
}
@Override public TASK pollTask() { @Override public TASK pollTask() {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
@ -185,8 +189,14 @@ public class BaseExecutePool<TASK extends AbsTask> implements IPool<TASK> {
} }
String convertKey = CommonUtil.keyToHashKey(key); String convertKey = CommonUtil.keyToHashKey(key);
TASK task = mExecuteMap.get(convertKey); TASK task = mExecuteMap.get(convertKey);
final int oldQueueSize = mExecuteQueue.size();
boolean isSuccess = mExecuteQueue.remove(task);
final int newQueueSize = mExecuteQueue.size();
if (isSuccess && newQueueSize != oldQueueSize) {
mExecuteMap.remove(convertKey); mExecuteMap.remove(convertKey);
return mExecuteQueue.remove(task); return true;
}
return false;
} }
} }

@ -41,20 +41,11 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY extends A
implements ISchedulers<TASK> { implements ISchedulers<TASK> {
private final String TAG = "AbsSchedulers"; private final String TAG = "AbsSchedulers";
static final int DOWNLOAD = 0xa1;
static final int UPLOAD = 0xa2;
static final int DOWNLOAD_GROUP = 0xa3;
protected QUEUE mQueue; protected QUEUE mQueue;
private Map<String, AbsSchedulerListener<TASK, AbsNormalEntity>> mObservers = private Map<String, AbsSchedulerListener<TASK, AbsNormalEntity>> mObservers =
new ConcurrentHashMap<>(); new ConcurrentHashMap<>();
/**
* 设置调度器类型
*/
abstract int getSchedulerType();
/** /**
* 设置代理类后缀名 * 设置代理类后缀名
*/ */
@ -282,7 +273,7 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY extends A
/** /**
* 启动下一个任务条件任务停止取消下载任务完成 * 启动下一个任务条件任务停止取消下载任务完成
*/ */
protected void startNextTask() { private void startNextTask() {
TASK newTask = mQueue.getNextTask(); TASK newTask = mQueue.getNextTask();
if (newTask == null) { if (newTask == null) {
Log.w(TAG, "没有下一任务"); Log.w(TAG, "没有下一任务");
@ -292,20 +283,4 @@ abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY extends A
mQueue.startTask(newTask); mQueue.startTask(newTask);
} }
} }
/**
* 是否有下一任务
*
* @return {@code true} {@code false}
*/
boolean hasNextTask() {
return mQueue.getCurrentCachePoolNum() > 0;
}
/**
* 获取正在执行的队列数
*/
int getExeTaskNum() {
return mQueue.getCurrentExePoolNum();
}
} }

@ -43,10 +43,6 @@ public class DownloadGroupSchedulers extends
return INSTANCE; return INSTANCE;
} }
@Override int getSchedulerType() {
return DOWNLOAD_GROUP;
}
@Override String getProxySuffix() { @Override String getProxySuffix() {
return "$$DownloadGroupListenerProxy"; return "$$DownloadGroupListenerProxy";
} }

@ -45,10 +45,6 @@ public class DownloadSchedulers
return INSTANCE; return INSTANCE;
} }
@Override int getSchedulerType() {
return DOWNLOAD;
}
@Override String getProxySuffix() { @Override String getProxySuffix() {
return "$$DownloadListenerProxy"; return "$$DownloadListenerProxy";
} }

@ -44,10 +44,6 @@ public class UploadSchedulers
return INSTANCE; return INSTANCE;
} }
@Override int getSchedulerType() {
return UPLOAD;
}
@Override String getProxySuffix() { @Override String getProxySuffix() {
return "$$UploadListenerProxy"; return "$$UploadListenerProxy";
} }

@ -31,12 +31,14 @@ import java.lang.ref.WeakReference;
class BaseUListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>> class BaseUListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>>
implements IUploadListener { implements IUploadListener {
private WeakReference<Handler> outHandler; private WeakReference<Handler> outHandler;
private int RUN_SAVE_INTERVAL = 5 * 1000; //5s保存一次下载中的进度
private long mLastLen = 0; //上一次发送长度 private long mLastLen = 0; //上一次发送长度
private boolean isFirst = true; private boolean isFirst = true;
protected ENTITY mEntity; protected ENTITY mEntity;
protected TASK mTask; protected TASK mTask;
private boolean isConvertSpeed = false; private boolean isConvertSpeed = false;
boolean isWait = false; boolean isWait = false;
private long mLastSaveTime;
BaseUListener(TASK task, Handler outHandler) { BaseUListener(TASK task, Handler outHandler) {
this.outHandler = new WeakReference<>(outHandler); this.outHandler = new WeakReference<>(outHandler);
@ -45,6 +47,7 @@ class BaseUListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>>
final AriaManager manager = AriaManager.getInstance(AriaManager.APP); final AriaManager manager = AriaManager.getInstance(AriaManager.APP);
isConvertSpeed = manager.getDownloadConfig().isConvertSpeed(); isConvertSpeed = manager.getDownloadConfig().isConvertSpeed();
mLastLen = mEntity.getCurrentProgress(); mLastLen = mEntity.getCurrentProgress();
mLastSaveTime = System.currentTimeMillis();
} }
@Override public void onPre() { @Override public void onPre() {
@ -71,6 +74,10 @@ class BaseUListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>>
} }
handleSpeed(speed); handleSpeed(speed);
sendInState2Target(ISchedulers.RUNNING); sendInState2Target(ISchedulers.RUNNING);
if (System.currentTimeMillis() - mLastSaveTime >= RUN_SAVE_INTERVAL) {
saveData(IEntity.STATE_RUNNING, currentLocation);
mLastSaveTime = System.currentTimeMillis();
}
mLastLen = currentLocation; mLastLen = currentLocation;
} }

@ -45,6 +45,9 @@ public class FtpUploadTarget
File file = new File(filePath); File file = new File(filePath);
mEntity.setFileName(file.getName()); mEntity.setFileName(file.getName());
mEntity.setFileSize(file.length()); mEntity.setFileSize(file.length());
//暂时不支持断点续传上传
//mTaskEntity.isSupportBP = false;
} }
/** /**

@ -0,0 +1,74 @@
/*
* 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.upload.uploader;
import android.support.annotation.NonNull;
import com.arialyy.aria.util.BufferedRandomAccessFile;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by lyy on 2017/9/26.
* BufferedRandomAccessFile InputStream 适配器
*/
final class FtpFISAdapter extends InputStream {
private BufferedRandomAccessFile mIs;
private ProgressCallback mCallback;
private int count;
interface ProgressCallback {
void onProgressCallback(byte[] buffer, int byteOffset, int byteCount) throws IOException;
}
FtpFISAdapter(@NonNull BufferedRandomAccessFile is, @NonNull ProgressCallback callback) {
mIs = is;
mCallback = callback;
}
FtpFISAdapter(@NonNull BufferedRandomAccessFile is) {
mIs = is;
}
@Override public void close() throws IOException {
mIs.close();
}
@Override public int read() throws IOException {
return mIs.read();
}
@Override public int read(@NonNull byte[] buffer) throws IOException {
count = mIs.read(buffer);
if (mCallback != null) {
mCallback.onProgressCallback(buffer, 0, count);
}
return count;
}
@Override public int read(@NonNull byte[] buffer, int byteOffset, int byteCount)
throws IOException {
count = mIs.read(buffer, byteOffset, byteCount);
if (mCallback != null) {
mCallback.onProgressCallback(buffer, byteOffset, byteCount);
}
return count;
}
@Override public long skip(long byteCount) throws IOException {
return mIs.skipBytes((int) byteCount);
}
}

@ -0,0 +1,78 @@
/*
* 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.upload.uploader;
import com.arialyy.aria.core.common.AbsFtpInfoThread;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.util.Properties;
import org.apache.commons.net.ftp.FTPFile;
/**
* Created by Aria.Lao on 2017/9/26.
* 单任务远程服务器文件信息
*/
class FtpFileInfoThread extends AbsFtpInfoThread<UploadEntity, UploadTaskEntity> {
static final int CODE_COMPLETE = 0xab1;
private boolean isComplete = false;
FtpFileInfoThread(UploadTaskEntity taskEntity, OnFileInfoCallback callback) {
super(taskEntity, callback);
}
@Override protected String setRemotePath() {
String url = mEntity.getUrl();
return url.substring(url.indexOf(mPort) + mPort.length(), url.length())
+ "/"
+ mEntity.getFileName();
}
/**
* 如果服务器的文件长度和本地上传文件的文件长度一致则任务任务已完成
* 否则重新修改保存的停止位置这是因为outputStream是读不到服务器是否成功写入的
* 而threadTask的保存的停止位置是File的InputStream的所有就会导致两端停止位置不一致
*
* @param remotePath ftp服务器文件夹路径
* @param ftpFile ftp服务器上对应的文件
*/
@Override protected void handleFile(String remotePath, FTPFile ftpFile) {
super.handleFile(remotePath, ftpFile);
if (ftpFile != null) {
//远程文件已完成
if (ftpFile.getSize() == mEntity.getFileSize()) {
isComplete = true;
} else {
File configFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName()));
Properties pro = CommonUtil.loadConfig(configFile);
String key = mEntity.getFileName() + "_record_" + 0;
long oldRecord = Long.parseLong(pro.getProperty(key, "0"));
if (oldRecord != 0) {
//修改本地保存的停止地址为服务器上的真实地址
pro.setProperty(key, ftpFile.getSize() + "");
CommonUtil.saveConfig(configFile, pro);
}
}
}
}
@Override protected void onPreComplete(int code) {
super.onPreComplete(code);
mCallback.onComplete(mEntity.getKey(), isComplete ? CODE_COMPLETE : code);
}
}

@ -15,9 +15,8 @@
*/ */
package com.arialyy.aria.core.upload.uploader; package com.arialyy.aria.core.upload.uploader;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.common.AbsThreadTask; import com.arialyy.aria.core.common.AbsFtpThreadTask;
import com.arialyy.aria.core.common.StateConstance; import com.arialyy.aria.core.common.StateConstance;
import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.common.SubThreadConfig;
import com.arialyy.aria.core.inf.IEventListener; import com.arialyy.aria.core.inf.IEventListener;
@ -26,29 +25,26 @@ import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.util.BufferedRandomAccessFile; import com.arialyy.aria.util.BufferedRandomAccessFile;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.UnsupportedEncodingException;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply; import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.OnFtpInputStreamListener;
/** /**
* Created by Aria.Lao on 2017/7/28. * Created by Aria.Lao on 2017/7/28.
* FTP 单线程上传任务需要FTP 服务器给用户打开删除和读入IO的权限 * FTP 单线程上传任务需要FTP 服务器给用户打开删除和读入IO的权限
*/ */
class FtpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> { class FtpThreadTask extends AbsFtpThreadTask<UploadEntity, UploadTaskEntity> {
private final String TAG = "FtpThreadTask"; private final String TAG = "FtpThreadTask";
private String dir, remotePath, charSet; private String dir, remotePath;
FtpThreadTask(StateConstance constance, IEventListener listener, FtpThreadTask(StateConstance constance, IEventListener listener,
SubThreadConfig<UploadTaskEntity> info) { SubThreadConfig<UploadTaskEntity> info) {
super(constance, listener, info); super(constance, listener, info);
} }
@Override public void run() { @Override public void run() {
FTPClient client = null; FTPClient client = null;
OutputStream os = null;
BufferedRandomAccessFile file = null; BufferedRandomAccessFile file = null;
try { try {
Log.d(TAG, "任务【" Log.d(TAG, "任务【"
@ -64,22 +60,16 @@ class FtpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
mChildCurrentLocation = mConfig.START_LOCATION; mChildCurrentLocation = mConfig.START_LOCATION;
client = createClient(); client = createClient();
if (client == null) return; if (client == null) return;
initPath();
client.makeDirectory(dir); client.makeDirectory(dir);
client.changeWorkingDirectory(dir); client.changeWorkingDirectory(dir);
client.setRestartOffset(mConfig.START_LOCATION); client.setRestartOffset(mConfig.START_LOCATION);
file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize); file = new BufferedRandomAccessFile(mConfig.TEMP_FILE, "rwd", mBufSize);
if (mConfig.START_LOCATION != 0) {
//file.skipBytes((int) mConfig.START_LOCATION);
file.seek(mConfig.START_LOCATION); file.seek(mConfig.START_LOCATION);
if (!isRemoteComplete(client)) {
os = client.storeFileStream(new String(remotePath.getBytes(charSet), SERVER_CHARSET));
//发送第二次指令时,还需要再做一次判断
int reply = client.getReplyCode();
if (!FTPReply.isPositivePreliminary(reply)) {
client.disconnect();
fail(mChildCurrentLocation, "上传文件错误,错误码为:" + reply, null);
return;
}
upload(file, os);
} }
upload(client, file);
if (STATE.isCancel || STATE.isStop) return; if (STATE.isCancel || STATE.isStop) return;
Log.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__上传完毕"); Log.i(TAG, "任务【" + mConfig.TEMP_FILE.getName() + "】线程__" + mConfig.THREAD_ID + "__上传完毕");
writeConfig(true, 1); writeConfig(true, 1);
@ -101,9 +91,6 @@ class FtpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
if (file != null) { if (file != null) {
file.close(); file.close();
} }
if (os != null) {
os.close();
}
if (client != null && client.isConnected()) { if (client != null && client.isConnected()) {
client.disconnect(); client.disconnect();
} }
@ -113,78 +100,52 @@ class FtpThreadTask extends AbsThreadTask<UploadEntity, UploadTaskEntity> {
} }
} }
/** private void initPath() throws UnsupportedEncodingException {
* 远程文件是否已经玩飞车 String url = mEntity.getUrl();
* String temp = url.substring(url.indexOf(port) + port.length(), url.length());
* @return true 任务已经完成 dir = new String(temp.getBytes(charSet), SERVER_CHARSET);
*/ remotePath = new String((temp + "/" + mEntity.getFileName()).getBytes(charSet), SERVER_CHARSET);
private boolean isRemoteComplete(FTPClient client) throws IOException {
FTPFile[] files = client.listFiles(new String(remotePath.getBytes(charSet), SERVER_CHARSET));
return files.length != 0 && files[0].getSize() == mEntity.getFileSize();
} }
/** private void upload(final FTPClient client, final BufferedRandomAccessFile bis)
* 执行上传操作 throws IOException {
*/
private void upload(BufferedRandomAccessFile file, OutputStream os) try {
throws IOException, InterruptedException { client.storeFile(remotePath, new FtpFISAdapter(bis), new OnFtpInputStreamListener() {
int len; boolean isStoped = false;
byte[] buffer = new byte[mBufSize];
while ((len = file.read(buffer)) != -1) { @Override public void onFtpInputStream(FTPClient client, long totalBytesTransferred,
if (STATE.isCancel) break; int bytesTransferred, long streamSize) {
if (STATE.isStop) break; if ((STATE.isCancel || STATE.isStop) && !isStoped) {
if (mSleepTime > 0) Thread.sleep(mSleepTime); try {
if (mChildCurrentLocation + len >= mConfig.END_LOCATION) { isStoped = true;
len = (int) (mConfig.END_LOCATION - mChildCurrentLocation); client.abor();
os.write(buffer, 0, len); } catch (IOException e) {
progress(len); e.printStackTrace();
break;
} else {
os.write(buffer, 0, len);
progress(len);
} }
} }
progress(bytesTransferred);
} }
});
/** } catch (IOException e) {
* 构建FTP客户端 if (e.getMessage().contains("IOException caught while copying")) {
*/ e.printStackTrace();
private FTPClient createClient() throws IOException {
String url = mEntity.getUrl();
String[] pp = url.split("/")[2].split(":");
String serverIp = pp[0];
int port = Integer.parseInt(pp[1]);
dir = url.substring(url.indexOf(pp[1]) + pp[1].length(), url.length());
remotePath = dir + "/" + mEntity.getFileName();
FTPClient client = new FTPClient();
client.connect(serverIp, port);
if (!TextUtils.isEmpty(mTaskEntity.account)) {
client.login(mTaskEntity.userName, mTaskEntity.userPw);
} else { } else {
client.login(mTaskEntity.userName, mTaskEntity.userPw, mTaskEntity.account); fail(mChildCurrentLocation, "上传失败", e);
}
} }
int reply = client.getReplyCode(); int reply = client.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) { if (!FTPReply.isPositiveCompletion(reply)) {
if (client.isConnected()) {
client.disconnect(); client.disconnect();
fail(STATE.CURRENT_LOCATION, "无法连接到ftp服务器,错误码为:" + reply, null); }
return null; if (reply == FTPReply.TRANSFER_ABORTED) return;
} fail(mChildCurrentLocation, "上传文件错误,错误码为:" + reply, null);
charSet = "UTF-8"; }
// 开启服务器对UTF-8的支持,如果服务器支持就用UTF-8编码
if (!TextUtils.isEmpty(mTaskEntity.charSet) || !FTPReply.isPositiveCompletion(
client.sendCommand("OPTS UTF8", "ON"))) {
charSet = mTaskEntity.charSet;
}
client.setControlEncoding(charSet);
client.setDataTimeout(STATE.READ_TIME_OUT);
client.enterLocalPassiveMode();
client.setFileType(FTP.BINARY_FILE_TYPE);
client.allocate(mBufSize);
return client;
} }
@Override protected String getTaskType() { @Override protected String getTaskType() {
return "FTP_UPLOAD"; return "FTP_UPLOAD";
} }
} }

@ -16,6 +16,7 @@
package com.arialyy.aria.core.upload.uploader; package com.arialyy.aria.core.upload.uploader;
import com.arialyy.aria.core.common.IUtil; import com.arialyy.aria.core.common.IUtil;
import com.arialyy.aria.core.common.OnFileInfoCallback;
import com.arialyy.aria.core.inf.IUploadListener; import com.arialyy.aria.core.inf.IUploadListener;
import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity; import com.arialyy.aria.core.upload.UploadTaskEntity;
@ -46,8 +47,20 @@ public class SimpleUploadUtil implements IUtil, Runnable {
@Override public void run() { @Override public void run() {
mListener.onPre(); mListener.onPre();
new FtpFileInfoThread(mTaskEntity, new OnFileInfoCallback() {
@Override public void onComplete(String url, int code) {
if (code == FtpFileInfoThread.CODE_COMPLETE) {
mListener.onComplete();
} else {
mUploader.start(); mUploader.start();
} }
}
@Override public void onFail(String url, String errorMsg) {
mListener.onFail(true);
}
}).start();
}
@Override public long getFileSize() { @Override public long getFileSize() {
return mUploader.getFileSize(); return mUploader.getFileSize();

@ -15,7 +15,6 @@
*/ */
package com.arialyy.aria.core.upload.uploader; package com.arialyy.aria.core.upload.uploader;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.common.AbsFileer; import com.arialyy.aria.core.common.AbsFileer;
import com.arialyy.aria.core.common.AbsThreadTask; import com.arialyy.aria.core.common.AbsThreadTask;
import com.arialyy.aria.core.common.SubThreadConfig; import com.arialyy.aria.core.common.SubThreadConfig;
@ -47,10 +46,7 @@ class Uploader extends AbsFileer<UploadEntity, UploadTaskEntity> {
* 5不支持断点则是新任务 * 5不支持断点则是新任务
*/ */
protected void checkTask() { protected void checkTask() {
mConfigFile = new File(mContext.getFilesDir().getPath() mConfigFile = new File(CommonUtil.getFileConfigPath(false, mEntity.getFileName()));
+ AriaManager.UPLOAD_TEMP_DIR
+ mEntity.getFileName()
+ ".properties");
if (!mTaskEntity.isSupportBP) { if (!mTaskEntity.isSupportBP) {
isNewTask = true; isNewTask = true;
return; return;

@ -230,7 +230,7 @@ final class SqlHelper extends SQLiteOpenHelper {
} }
/** /**
* 遍历所有数据 * 查找表的所有数据
*/ */
static synchronized <T extends DbEntity> List<T> findAllData(SQLiteDatabase db, Class<T> clazz) { static synchronized <T extends DbEntity> List<T> findAllData(SQLiteDatabase db, Class<T> clazz) {
db = checkDb(db); db = checkDb(db);

@ -266,7 +266,7 @@ public class CommonUtil {
file.delete(); file.delete();
} }
} }
File config = new File(getFileConfig(false, uEntity.getFileName())); File config = new File(getFileConfigPath(false, uEntity.getFileName()));
if (config.exists()) { if (config.exists()) {
config.delete(); config.delete();
} }
@ -296,7 +296,7 @@ public class CommonUtil {
} }
} }
File config = new File(getFileConfig(true, dEntity.getFileName())); File config = new File(getFileConfigPath(true, dEntity.getFileName()));
if (config.exists()) { if (config.exists()) {
config.delete(); config.delete();
} }
@ -705,6 +705,7 @@ public class CommonUtil {
* 设置打印的异常格式 * 设置打印的异常格式
*/ */
public static String getPrintException(Throwable ex) { public static String getPrintException(Throwable ex) {
if (ex == null) return "";
StringBuilder err = new StringBuilder(); StringBuilder err = new StringBuilder();
err.append("ExceptionDetailed:\n"); err.append("ExceptionDetailed:\n");
err.append("====================Exception Info====================\n"); err.append("====================Exception Info====================\n");
@ -729,11 +730,11 @@ public class CommonUtil {
} }
/** /**
* 通过文件名获取下载配置文件 * 通过文件名获取下载配置文件路径
* *
* @param fileName 文件名 * @param fileName 文件名
*/ */
public static String getFileConfig(boolean isDownload, String fileName) { public static String getFileConfigPath(boolean isDownload, String fileName) {
return AriaManager.APP.getFilesDir().getPath() + (isDownload ? AriaManager.DOWNLOAD_TEMP_DIR return AriaManager.APP.getFilesDir().getPath() + (isDownload ? AriaManager.DOWNLOAD_TEMP_DIR
: AriaManager.UPLOAD_TEMP_DIR) + fileName + ".properties"; : AriaManager.UPLOAD_TEMP_DIR) + fileName + ".properties";
} }
@ -764,8 +765,8 @@ public class CommonUtil {
private static void renameConfig(boolean isDownload, String oldName, String newName) { private static void renameConfig(boolean isDownload, String oldName, String newName) {
if (oldName.equals(newName)) return; if (oldName.equals(newName)) return;
File oldFile = new File(getFileConfig(isDownload, oldName)); File oldFile = new File(getFileConfigPath(isDownload, oldName));
File newFile = new File(getFileConfig(isDownload, oldName)); File newFile = new File(getFileConfigPath(isDownload, oldName));
if (!oldFile.exists()) { if (!oldFile.exists()) {
createFile(newFile.getPath()); createFile(newFile.getPath());
} else { } else {

@ -0,0 +1,136 @@
/*
* 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 com.arialyy.aria.util;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
/**
* 跟网络相关的工具类
*/
public class NetUtils {
/**
* 没有网络
*/
public static final int NETWORK_TYPE_INVALID = 0;
/**
* wap网络
*/
public static final int NETWORK_TYPE_WAP = 1;
/**
* 2G网络
*/
public static final int NETWORK_TYPE_2G = 2;
/**
* 3G和3G以上网络或统称为快速网络
*/
public static final int NETWORK_TYPE_3G = 3;
/**
* wifi网络
*/
public static final int NETWORK_TYPE_WIFI = 4;
/**
* 判断网络是否连接
*/
public static boolean isConnected(Context context) {
ConnectivityManager cm =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
return ni != null && ni.isConnectedOrConnecting();
}
/**
* 判断是否是wifi连接
*/
public static boolean isWifi(Context context) {
return getNetWorkType(context) == NETWORK_TYPE_WIFI;
}
/**
* 获取网络状态wifi,wap,2g,3g.
*
* @param context 上下文
* @return int 网络状态 {@link #NETWORK_TYPE_2G},{@link #NETWORK_TYPE_3G},
* {@link #NETWORK_TYPE_INVALID},{@link #NETWORK_TYPE_WAP},{@link #NETWORK_TYPE_WIFI}
*/
public static int getNetWorkType(Context context) {
int netWorkType = -1;
ConnectivityManager manager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
String type = networkInfo.getTypeName();
if (type.equalsIgnoreCase("WIFI")) {
netWorkType = NETWORK_TYPE_WIFI;
} else if (type.equalsIgnoreCase("MOBILE")) {
String proxyHost = android.net.Proxy.getDefaultHost();
netWorkType = TextUtils.isEmpty(proxyHost) ? (isFastMobileNetwork(context) ? NETWORK_TYPE_3G
: NETWORK_TYPE_2G) : NETWORK_TYPE_WAP;
}
} else {
netWorkType = NETWORK_TYPE_INVALID;
}
return netWorkType;
}
private static boolean isFastMobileNetwork(Context context) {
TelephonyManager telephonyManager =
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
switch (telephonyManager.getNetworkType()) {
case TelephonyManager.NETWORK_TYPE_1xRTT:
return false; // ~ 50-100 kbps
case TelephonyManager.NETWORK_TYPE_CDMA:
return false; // ~ 14-64 kbps
case TelephonyManager.NETWORK_TYPE_EDGE:
return false; // ~ 50-100 kbps
case TelephonyManager.NETWORK_TYPE_EVDO_0:
return true; // ~ 400-1000 kbps
case TelephonyManager.NETWORK_TYPE_EVDO_A:
return true; // ~ 600-1400 kbps
case TelephonyManager.NETWORK_TYPE_GPRS:
return false; // ~ 100 kbps
case TelephonyManager.NETWORK_TYPE_HSDPA:
return true; // ~ 2-14 Mbps
case TelephonyManager.NETWORK_TYPE_HSPA:
return true; // ~ 700-1700 kbps
case TelephonyManager.NETWORK_TYPE_HSUPA:
return true; // ~ 1-23 Mbps
case TelephonyManager.NETWORK_TYPE_UMTS:
return true; // ~ 400-7000 kbps
case TelephonyManager.NETWORK_TYPE_EHRPD:
return true; // ~ 1-2 Mbps
case TelephonyManager.NETWORK_TYPE_EVDO_B:
return true; // ~ 5 Mbps
case TelephonyManager.NETWORK_TYPE_HSPAP:
return true; // ~ 10-20 Mbps
case TelephonyManager.NETWORK_TYPE_IDEN:
return false; // ~25 kbps
case TelephonyManager.NETWORK_TYPE_LTE:
return true; // ~ 10+ Mbps
case TelephonyManager.NETWORK_TYPE_UNKNOWN:
return false;
default:
return false;
}
}
}

@ -3,7 +3,7 @@ publish {
artifactId = 'aria-ftp-plug' artifactId = 'aria-ftp-plug'
userOrg = rootProject.userOrg userOrg = rootProject.userOrg
groupId = rootProject.groupId groupId = rootProject.groupId
uploadName = 'AriaFtpPlug' uploadName = 'FtpPlug'
publishVersion = rootProject.publishVersion publishVersion = rootProject.publishVersion
description = rootProject.description description = rootProject.description
website = rootProject.website website = rootProject.website

@ -47,8 +47,7 @@ import java.nio.charset.Charset;
* @see DatagramSocketFactory * @see DatagramSocketFactory
***/ ***/
public abstract class DatagramSocketClient public abstract class DatagramSocketClient {
{
/*** /***
* The default DatagramSocketFactory shared by all DatagramSocketClient * The default DatagramSocketFactory shared by all DatagramSocketClient
* instances. * instances.
@ -79,15 +78,13 @@ public abstract class DatagramSocketClient
* Default constructor for DatagramSocketClient. Initializes * Default constructor for DatagramSocketClient. Initializes
* _socket_ to null, _timeout_ to 0, and _isOpen_ to false. * _socket_ to null, _timeout_ to 0, and _isOpen_ to false.
***/ ***/
public DatagramSocketClient() public DatagramSocketClient() {
{
_socket_ = null; _socket_ = null;
_timeout_ = 0; _timeout_ = 0;
_isOpen_ = false; _isOpen_ = false;
_socketFactory_ = __DEFAULT_SOCKET_FACTORY; _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
} }
/*** /***
* Opens a DatagramSocket on the local host at the first available port. * Opens a DatagramSocket on the local host at the first available port.
* Also sets the timeout on the socket to the default timeout set * Also sets the timeout on the socket to the default timeout set
@ -99,14 +96,12 @@ public abstract class DatagramSocketClient
* @throws SocketException If the socket could not be opened or the * @throws SocketException If the socket could not be opened or the
* timeout could not be set. * timeout could not be set.
***/ ***/
public void open() throws SocketException public void open() throws SocketException {
{
_socket_ = _socketFactory_.createDatagramSocket(); _socket_ = _socketFactory_.createDatagramSocket();
_socket_.setSoTimeout(_timeout_); _socket_.setSoTimeout(_timeout_);
_isOpen_ = true; _isOpen_ = true;
} }
/*** /***
* Opens a DatagramSocket on the local host at a specified port. * Opens a DatagramSocket on the local host at a specified port.
* Also sets the timeout on the socket to the default timeout set * Also sets the timeout on the socket to the default timeout set
@ -119,14 +114,12 @@ public abstract class DatagramSocketClient
* @throws SocketException If the socket could not be opened or the * @throws SocketException If the socket could not be opened or the
* timeout could not be set. * timeout could not be set.
***/ ***/
public void open(int port) throws SocketException public void open(int port) throws SocketException {
{
_socket_ = _socketFactory_.createDatagramSocket(port); _socket_ = _socketFactory_.createDatagramSocket(port);
_socket_.setSoTimeout(_timeout_); _socket_.setSoTimeout(_timeout_);
_isOpen_ = true; _isOpen_ = true;
} }
/*** /***
* Opens a DatagramSocket at the specified address on the local host * Opens a DatagramSocket at the specified address on the local host
* at a specified port. * at a specified port.
@ -141,23 +134,19 @@ public abstract class DatagramSocketClient
* @throws SocketException If the socket could not be opened or the * @throws SocketException If the socket could not be opened or the
* timeout could not be set. * timeout could not be set.
***/ ***/
public void open(int port, InetAddress laddr) throws SocketException public void open(int port, InetAddress laddr) throws SocketException {
{
_socket_ = _socketFactory_.createDatagramSocket(port, laddr); _socket_ = _socketFactory_.createDatagramSocket(port, laddr);
_socket_.setSoTimeout(_timeout_); _socket_.setSoTimeout(_timeout_);
_isOpen_ = true; _isOpen_ = true;
} }
/*** /***
* Closes the DatagramSocket used for the connection. * Closes the DatagramSocket used for the connection.
* You should call this method after you've finished using the class * You should call this method after you've finished using the class
* instance and also before you call {@link #open open() } * instance and also before you call {@link #open open() }
* again. _isOpen_ is set to false and _socket_ is set to null. * again. _isOpen_ is set to false and _socket_ is set to null.
***/ ***/
public void close() public void close() {
{
if (_socket_ != null) { if (_socket_ != null) {
_socket_.close(); _socket_.close();
} }
@ -165,18 +154,15 @@ public abstract class DatagramSocketClient
_isOpen_ = false; _isOpen_ = false;
} }
/*** /***
* Returns true if the client has a currently open socket. * Returns true if the client has a currently open socket.
* *
* @return True if the client has a currently open socket, false otherwise. * @return True if the client has a currently open socket, false otherwise.
***/ ***/
public boolean isOpen() public boolean isOpen() {
{
return _isOpen_; return _isOpen_;
} }
/*** /***
* Set the default timeout in milliseconds to use when opening a socket. * 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. * After a call to open, the timeout for the socket is set using this value.
@ -188,12 +174,10 @@ public abstract class DatagramSocketClient
* @param timeout The timeout in milliseconds to use for the datagram socket * @param timeout The timeout in milliseconds to use for the datagram socket
* connection. * connection.
***/ ***/
public void setDefaultTimeout(int timeout) public void setDefaultTimeout(int timeout) {
{
_timeout_ = timeout; _timeout_ = timeout;
} }
/*** /***
* Returns the default timeout in milliseconds that is used when * Returns the default timeout in milliseconds that is used when
* opening a socket. * opening a socket.
@ -201,12 +185,10 @@ public abstract class DatagramSocketClient
* @return The default timeout in milliseconds that is used when * @return The default timeout in milliseconds that is used when
* opening a socket. * opening a socket.
***/ ***/
public int getDefaultTimeout() public int getDefaultTimeout() {
{
return _timeout_; return _timeout_;
} }
/*** /***
* Set the timeout in milliseconds of a currently open connection. * Set the timeout in milliseconds of a currently open connection.
* Only call this method after a connection has been opened * Only call this method after a connection has been opened
@ -216,12 +198,10 @@ public abstract class DatagramSocketClient
* open datagram socket connection. * open datagram socket connection.
* @throws SocketException if an error setting the timeout * @throws SocketException if an error setting the timeout
***/ ***/
public void setSoTimeout(int timeout) throws SocketException public void setSoTimeout(int timeout) throws SocketException {
{
_socket_.setSoTimeout(timeout); _socket_.setSoTimeout(timeout);
} }
/*** /***
* Returns the timeout in milliseconds of the currently opened socket. * Returns the timeout in milliseconds of the currently opened socket.
* If you call this method when the client socket is not open, * If you call this method when the client socket is not open,
@ -230,12 +210,10 @@ public abstract class DatagramSocketClient
* @return The timeout in milliseconds of the currently opened socket. * @return The timeout in milliseconds of the currently opened socket.
* @throws SocketException if an error getting the timeout * @throws SocketException if an error getting the timeout
***/ ***/
public int getSoTimeout() throws SocketException public int getSoTimeout() throws SocketException {
{
return _socket_.getSoTimeout(); return _socket_.getSoTimeout();
} }
/*** /***
* Returns the port number of the open socket on the local host used * 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 * for the connection. If you call this method when the client socket
@ -244,12 +222,10 @@ public abstract class DatagramSocketClient
* @return The port number of the open socket on the local host used * @return The port number of the open socket on the local host used
* for the connection. * for the connection.
***/ ***/
public int getLocalPort() public int getLocalPort() {
{
return _socket_.getLocalPort(); return _socket_.getLocalPort();
} }
/*** /***
* Returns the local address to which the client's socket is bound. * 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 * If you call this method when the client socket is not open, a
@ -257,12 +233,10 @@ public abstract class DatagramSocketClient
* *
* @return The local address to which the client's socket is bound. * @return The local address to which the client's socket is bound.
***/ ***/
public InetAddress getLocalAddress() public InetAddress getLocalAddress() {
{
return _socket_.getLocalAddress(); return _socket_.getLocalAddress();
} }
/*** /***
* Sets the DatagramSocketFactory used by the DatagramSocketClient * Sets the DatagramSocketFactory used by the DatagramSocketClient
* to open DatagramSockets. If the factory value is null, then a default * to open DatagramSockets. If the factory value is null, then a default
@ -272,8 +246,7 @@ public abstract class DatagramSocketClient
* @param factory The new DatagramSocketFactory the DatagramSocketClient * @param factory The new DatagramSocketFactory the DatagramSocketClient
* should use. * should use.
***/ ***/
public void setDatagramSocketFactory(DatagramSocketFactory factory) public void setDatagramSocketFactory(DatagramSocketFactory factory) {
{
if (factory == null) { if (factory == null) {
_socketFactory_ = __DEFAULT_SOCKET_FACTORY; _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
} else { } else {

@ -35,8 +35,7 @@ import java.net.SocketException;
* *
***/ ***/
public interface DatagramSocketFactory public interface DatagramSocketFactory {
{
/*** /***
* Creates a DatagramSocket on the local host at the first available port. * Creates a DatagramSocket on the local host at the first available port.
@ -64,6 +63,5 @@ public interface DatagramSocketFactory
* @return the socket * @return the socket
* @throws SocketException If the socket could not be created. * @throws SocketException If the socket could not be created.
***/ ***/
public DatagramSocket createDatagramSocket(int port, InetAddress laddr) public DatagramSocket createDatagramSocket(int port, InetAddress laddr) throws SocketException;
throws SocketException;
} }

@ -34,17 +34,14 @@ import java.net.SocketException;
* @see DatagramSocketClient#setDatagramSocketFactory * @see DatagramSocketClient#setDatagramSocketFactory
***/ ***/
public class DefaultDatagramSocketFactory implements DatagramSocketFactory public class DefaultDatagramSocketFactory implements DatagramSocketFactory {
{
/*** /***
* Creates a DatagramSocket on the local host at the first available port. * Creates a DatagramSocket on the local host at the first available port.
* @return a new DatagramSocket * @return a new DatagramSocket
* @throws SocketException If the socket could not be created. * @throws SocketException If the socket could not be created.
***/ ***/
@Override @Override public DatagramSocket createDatagramSocket() throws SocketException {
public DatagramSocket createDatagramSocket() throws SocketException
{
return new DatagramSocket(); return new DatagramSocket();
} }
@ -55,9 +52,7 @@ public class DefaultDatagramSocketFactory implements DatagramSocketFactory
* @return a new DatagramSocket * @return a new DatagramSocket
* @throws SocketException If the socket could not be created. * @throws SocketException If the socket could not be created.
***/ ***/
@Override @Override public DatagramSocket createDatagramSocket(int port) throws SocketException {
public DatagramSocket createDatagramSocket(int port) throws SocketException
{
return new DatagramSocket(port); return new DatagramSocket(port);
} }
@ -70,10 +65,8 @@ public class DefaultDatagramSocketFactory implements DatagramSocketFactory
* @return a new DatagramSocket * @return a new DatagramSocket
* @throws SocketException If the socket could not be created. * @throws SocketException If the socket could not be created.
***/ ***/
@Override @Override public DatagramSocket createDatagramSocket(int port, InetAddress laddr)
public DatagramSocket createDatagramSocket(int port, InetAddress laddr) throws SocketException {
throws SocketException
{
return new DatagramSocket(port, laddr); return new DatagramSocket(port, laddr);
} }
} }

@ -40,16 +40,14 @@ import javax.net.SocketFactory;
* @see SocketClient#setSocketFactory * @see SocketClient#setSocketFactory
***/ ***/
public class DefaultSocketFactory extends SocketFactory public class DefaultSocketFactory extends SocketFactory {
{
/** The proxy to use when creating new sockets. */ /** The proxy to use when creating new sockets. */
private final Proxy connProxy; private final Proxy connProxy;
/** /**
* The default constructor. * The default constructor.
*/ */
public DefaultSocketFactory() public DefaultSocketFactory() {
{
this(null); this(null);
} }
@ -59,8 +57,7 @@ public class DefaultSocketFactory extends SocketFactory
* @param proxy The Proxy to use when creating new Sockets. * @param proxy The Proxy to use when creating new Sockets.
* @since 3.2 * @since 3.2
*/ */
public DefaultSocketFactory(Proxy proxy) public DefaultSocketFactory(Proxy proxy) {
{
connProxy = proxy; connProxy = proxy;
} }
@ -71,11 +68,8 @@ public class DefaultSocketFactory extends SocketFactory
* @throws IOException If an I/O error occurs while creating the Socket. * @throws IOException If an I/O error occurs while creating the Socket.
* @since 3.2 * @since 3.2
*/ */
@Override @Override public Socket createSocket() throws IOException {
public Socket createSocket() throws IOException if (connProxy != null) {
{
if (connProxy != null)
{
return new Socket(connProxy); return new Socket(connProxy);
} }
return new Socket(); return new Socket();
@ -90,12 +84,9 @@ public class DefaultSocketFactory extends SocketFactory
* @throws UnknownHostException If the hostname cannot be resolved. * @throws UnknownHostException If the hostname cannot be resolved.
* @throws IOException If an I/O error occurs while creating the Socket. * @throws IOException If an I/O error occurs while creating the Socket.
***/ ***/
@Override @Override public Socket createSocket(String host, int port)
public Socket createSocket(String host, int port) throws UnknownHostException, IOException {
throws UnknownHostException, IOException if (connProxy != null) {
{
if (connProxy != null)
{
Socket s = new Socket(connProxy); Socket s = new Socket(connProxy);
s.connect(new InetSocketAddress(host, port)); s.connect(new InetSocketAddress(host, port));
return s; return s;
@ -111,12 +102,8 @@ public class DefaultSocketFactory extends SocketFactory
* @return A Socket connected to the given host and port. * @return A Socket connected to the given host and port.
* @throws IOException If an I/O error occurs while creating the Socket. * @throws IOException If an I/O error occurs while creating the Socket.
***/ ***/
@Override @Override public Socket createSocket(InetAddress address, int port) throws IOException {
public Socket createSocket(InetAddress address, int port) if (connProxy != null) {
throws IOException
{
if (connProxy != null)
{
Socket s = new Socket(connProxy); Socket s = new Socket(connProxy);
s.connect(new InetSocketAddress(address, port)); s.connect(new InetSocketAddress(address, port));
return s; return s;
@ -136,13 +123,9 @@ public class DefaultSocketFactory extends SocketFactory
* @throws UnknownHostException If the hostname cannot be resolved. * @throws UnknownHostException If the hostname cannot be resolved.
* @throws IOException If an I/O error occurs while creating the Socket. * @throws IOException If an I/O error occurs while creating the Socket.
***/ ***/
@Override @Override public Socket createSocket(String host, int port, InetAddress localAddr, int localPort)
public Socket createSocket(String host, int port, throws UnknownHostException, IOException {
InetAddress localAddr, int localPort) if (connProxy != null) {
throws UnknownHostException, IOException
{
if (connProxy != null)
{
Socket s = new Socket(connProxy); Socket s = new Socket(connProxy);
s.bind(new InetSocketAddress(localAddr, localPort)); s.bind(new InetSocketAddress(localAddr, localPort));
s.connect(new InetSocketAddress(host, port)); s.connect(new InetSocketAddress(host, port));
@ -162,13 +145,9 @@ public class DefaultSocketFactory extends SocketFactory
* @return A Socket connected to the given host and port. * @return A Socket connected to the given host and port.
* @throws IOException If an I/O error occurs while creating the Socket. * @throws IOException If an I/O error occurs while creating the Socket.
***/ ***/
@Override @Override public Socket createSocket(InetAddress address, int port, InetAddress localAddr,
public Socket createSocket(InetAddress address, int port, int localPort) throws IOException {
InetAddress localAddr, int localPort) if (connProxy != null) {
throws IOException
{
if (connProxy != null)
{
Socket s = new Socket(connProxy); Socket s = new Socket(connProxy);
s.bind(new InetSocketAddress(localAddr, localPort)); s.bind(new InetSocketAddress(localAddr, localPort));
s.connect(new InetSocketAddress(address, port)); s.connect(new InetSocketAddress(address, port));
@ -186,8 +165,7 @@ public class DefaultSocketFactory extends SocketFactory
* @throws IOException If an I/O error occurs while creating * @throws IOException If an I/O error occurs while creating
* the ServerSocket. * the ServerSocket.
***/ ***/
public ServerSocket createServerSocket(int port) throws IOException public ServerSocket createServerSocket(int port) throws IOException {
{
return new ServerSocket(port); return new ServerSocket(port);
} }
@ -202,9 +180,7 @@ public class DefaultSocketFactory extends SocketFactory
* @throws IOException If an I/O error occurs while creating * @throws IOException If an I/O error occurs while creating
* the ServerSocket. * the ServerSocket.
***/ ***/
public ServerSocket createServerSocket(int port, int backlog) public ServerSocket createServerSocket(int port, int backlog) throws IOException {
throws IOException
{
return new ServerSocket(port, backlog); return new ServerSocket(port, backlog);
} }
@ -221,10 +197,8 @@ public class DefaultSocketFactory extends SocketFactory
* @throws IOException If an I/O error occurs while creating * @throws IOException If an I/O error occurs while creating
* the ServerSocket. * the ServerSocket.
***/ ***/
public ServerSocket createServerSocket(int port, int backlog, public ServerSocket createServerSocket(int port, int backlog, InetAddress bindAddr)
InetAddress bindAddr) throws IOException {
throws IOException
{
return new ServerSocket(port, backlog, bindAddr); return new ServerSocket(port, backlog, bindAddr);
} }
} }

@ -32,14 +32,12 @@ import java.io.IOException;
* *
***/ ***/
public class MalformedServerReplyException extends IOException public class MalformedServerReplyException extends IOException {
{
private static final long serialVersionUID = 6006765264250543945L; private static final long serialVersionUID = 6006765264250543945L;
/*** Constructs a MalformedServerReplyException with no message ***/ /*** Constructs a MalformedServerReplyException with no message ***/
public MalformedServerReplyException() public MalformedServerReplyException() {
{
super(); super();
} }
@ -48,9 +46,7 @@ public class MalformedServerReplyException extends IOException
* *
* @param message The message explaining the reason for the exception. * @param message The message explaining the reason for the exception.
***/ ***/
public MalformedServerReplyException(String message) public MalformedServerReplyException(String message) {
{
super(message); super(message);
} }
} }

@ -28,8 +28,7 @@ import java.io.PrintWriter;
* @since 2.0 * @since 2.0
***/ ***/
public class PrintCommandListener implements ProtocolCommandListener public class PrintCommandListener implements ProtocolCommandListener {
{
private final PrintWriter __writer; private final PrintWriter __writer;
private final boolean __nologin; private final boolean __nologin;
private final char __eolMarker; private final char __eolMarker;
@ -42,8 +41,7 @@ public class PrintCommandListener implements ProtocolCommandListener
* e.g. System.out * e.g. System.out
* @since 3.0 * @since 3.0
*/ */
public PrintCommandListener(PrintStream stream) public PrintCommandListener(PrintStream stream) {
{
this(new PrintWriter(stream)); this(new PrintWriter(stream));
} }
@ -53,7 +51,6 @@ public class PrintCommandListener implements ProtocolCommandListener
* *
* @param stream where to write the commands and responses * @param stream where to write the commands and responses
* @param suppressLogin if {@code true}, only print command name for login * @param suppressLogin if {@code true}, only print command name for login
*
* @since 3.0 * @since 3.0
*/ */
public PrintCommandListener(PrintStream stream, boolean suppressLogin) { public PrintCommandListener(PrintStream stream, boolean suppressLogin) {
@ -67,7 +64,6 @@ public class PrintCommandListener implements ProtocolCommandListener
* @param stream where to write the commands and responses * @param stream where to write the commands and responses
* @param suppressLogin if {@code true}, only print command name for login * @param suppressLogin if {@code true}, only print command name for login
* @param eolMarker if non-zero, add a marker just before the EOL. * @param eolMarker if non-zero, add a marker just before the EOL.
*
* @since 3.0 * @since 3.0
*/ */
public PrintCommandListener(PrintStream stream, boolean suppressLogin, char eolMarker) { public PrintCommandListener(PrintStream stream, boolean suppressLogin, char eolMarker) {
@ -81,11 +77,12 @@ public class PrintCommandListener implements ProtocolCommandListener
* @param stream where to write the commands and responses * @param stream where to write the commands and responses
* @param suppressLogin if {@code true}, only print command name for login * @param suppressLogin if {@code true}, only print command name for login
* @param eolMarker if non-zero, add a marker just before the EOL. * @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 * @param showDirection if {@code true}, add {@code "> "} or {@code "< "} as appropriate to the
* * output
* @since 3.0 * @since 3.0
*/ */
public PrintCommandListener(PrintStream stream, boolean suppressLogin, char eolMarker, boolean showDirection) { public PrintCommandListener(PrintStream stream, boolean suppressLogin, char eolMarker,
boolean showDirection) {
this(new PrintWriter(stream), suppressLogin, eolMarker, showDirection); this(new PrintWriter(stream), suppressLogin, eolMarker, showDirection);
} }
@ -94,8 +91,7 @@ public class PrintCommandListener implements ProtocolCommandListener
* *
* @param writer where to write the commands and responses * @param writer where to write the commands and responses
*/ */
public PrintCommandListener(PrintWriter writer) public PrintCommandListener(PrintWriter writer) {
{
this(writer, false); this(writer, false);
} }
@ -104,11 +100,9 @@ public class PrintCommandListener implements ProtocolCommandListener
* *
* @param writer where to write the commands and responses * @param writer where to write the commands and responses
* @param suppressLogin if {@code true}, only print command name for login * @param suppressLogin if {@code true}, only print command name for login
*
* @since 3.0 * @since 3.0
*/ */
public PrintCommandListener(PrintWriter writer, boolean suppressLogin) public PrintCommandListener(PrintWriter writer, boolean suppressLogin) {
{
this(writer, suppressLogin, (char) 0); this(writer, suppressLogin, (char) 0);
} }
@ -119,11 +113,9 @@ public class PrintCommandListener implements ProtocolCommandListener
* @param writer where to write the commands and responses * @param writer where to write the commands and responses
* @param suppressLogin if {@code true}, only print command name for login * @param suppressLogin if {@code true}, only print command name for login
* @param eolMarker if non-zero, add a marker just before the EOL. * @param eolMarker if non-zero, add a marker just before the EOL.
*
* @since 3.0 * @since 3.0
*/ */
public PrintCommandListener(PrintWriter writer, boolean suppressLogin, char eolMarker) public PrintCommandListener(PrintWriter writer, boolean suppressLogin, char eolMarker) {
{
this(writer, suppressLogin, eolMarker, false); this(writer, suppressLogin, eolMarker, false);
} }
@ -134,21 +126,19 @@ public class PrintCommandListener implements ProtocolCommandListener
* @param writer where to write the commands and responses * @param writer where to write the commands and responses
* @param suppressLogin if {@code true}, only print command name for login * @param suppressLogin if {@code true}, only print command name for login
* @param eolMarker if non-zero, add a marker just before the EOL. * @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 * @param showDirection if {@code true}, add {@code ">} " or {@code "< "} as appropriate to the
* * output
* @since 3.0 * @since 3.0
*/ */
public PrintCommandListener(PrintWriter writer, boolean suppressLogin, char eolMarker, boolean showDirection) public PrintCommandListener(PrintWriter writer, boolean suppressLogin, char eolMarker,
{ boolean showDirection) {
__writer = writer; __writer = writer;
__nologin = suppressLogin; __nologin = suppressLogin;
__eolMarker = eolMarker; __eolMarker = eolMarker;
__directionMarker = showDirection; __directionMarker = showDirection;
} }
@Override @Override public void protocolCommandSent(ProtocolCommandEvent event) {
public void protocolCommandSent(ProtocolCommandEvent event)
{
if (__directionMarker) { if (__directionMarker) {
__writer.print("> "); __writer.print("> ");
} }
@ -161,7 +151,7 @@ public class PrintCommandListener implements ProtocolCommandListener
final String IMAP_LOGIN = "LOGIN"; final String IMAP_LOGIN = "LOGIN";
if (IMAP_LOGIN.equalsIgnoreCase(cmd)) { // IMAP if (IMAP_LOGIN.equalsIgnoreCase(cmd)) { // IMAP
String msg = event.getMessage(); String msg = event.getMessage();
msg=msg.substring(0, msg.indexOf(IMAP_LOGIN)+IMAP_LOGIN.length()); msg = msg.substring(0, msg.indexOf(IMAP_LOGIN) + IMAP_LOGIN.length());
__writer.print(msg); __writer.print(msg);
__writer.println(" *******"); // Don't bother with EOL marker for this! __writer.println(" *******"); // Don't bother with EOL marker for this!
} else { } else {
@ -174,14 +164,14 @@ public class PrintCommandListener implements ProtocolCommandListener
__writer.flush(); __writer.flush();
} }
private String getPrintableString(String msg){ private String getPrintableString(String msg) {
if (__eolMarker == 0) { if (__eolMarker == 0) {
return msg; return msg;
} }
int pos = msg.indexOf(SocketClient.NETASCII_EOL); int pos = msg.indexOf(SocketClient.NETASCII_EOL);
if (pos > 0) { if (pos > 0) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(msg.substring(0,pos)); sb.append(msg.substring(0, pos));
sb.append(__eolMarker); sb.append(__eolMarker);
sb.append(msg.substring(pos)); sb.append(msg.substring(pos));
return sb.toString(); return sb.toString();
@ -189,9 +179,7 @@ public class PrintCommandListener implements ProtocolCommandListener
return msg; return msg;
} }
@Override @Override public void protocolReplyReceived(ProtocolCommandEvent event) {
public void protocolReplyReceived(ProtocolCommandEvent event)
{
if (__directionMarker) { if (__directionMarker) {
__writer.print("< "); __writer.print("< ");
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net; package org.apache.commons.net;
import java.util.EventObject; import java.util.EventObject;
/*** /***
@ -32,8 +33,7 @@ import java.util.EventObject;
* @see ProtocolCommandSupport * @see ProtocolCommandSupport
***/ ***/
public class ProtocolCommandEvent extends EventObject public class ProtocolCommandEvent extends EventObject {
{
private static final long serialVersionUID = 403743538418947240L; private static final long serialVersionUID = 403743538418947240L;
private final int __replyCode; private final int __replyCode;
@ -52,8 +52,7 @@ public class ProtocolCommandEvent extends EventObject
* @param message The entire command string verbatim as sent to the server, * @param message The entire command string verbatim as sent to the server,
* including all arguments. * including all arguments.
***/ ***/
public ProtocolCommandEvent(Object source, String command, String message) public ProtocolCommandEvent(Object source, String command, String message) {
{
super(source); super(source);
__replyCode = 0; __replyCode = 0;
__message = message; __message = message;
@ -61,7 +60,6 @@ public class ProtocolCommandEvent extends EventObject
__command = command; __command = command;
} }
/*** /***
* Creates a ProtocolCommandEvent signalling a reply to a command was * Creates a ProtocolCommandEvent signalling a reply to a command was
* received. ProtocolCommandEvents created with this constructor * received. ProtocolCommandEvents created with this constructor
@ -76,8 +74,7 @@ public class ProtocolCommandEvent extends EventObject
* strings like OK rather than integer codes (i.e., POP3Repy.OK). * strings like OK rather than integer codes (i.e., POP3Repy.OK).
* @param message The entire reply as received from the server. * @param message The entire reply as received from the server.
***/ ***/
public ProtocolCommandEvent(Object source, int replyCode, String message) public ProtocolCommandEvent(Object source, int replyCode, String message) {
{
super(source); super(source);
__replyCode = replyCode; __replyCode = replyCode;
__message = message; __message = message;
@ -93,12 +90,10 @@ public class ProtocolCommandEvent extends EventObject
* @return The string representation of the command type sent, or null * @return The string representation of the command type sent, or null
* if this is a reply event. * if this is a reply event.
***/ ***/
public String getCommand() public String getCommand() {
{
return __command; return __command;
} }
/*** /***
* Returns the reply code of the received server reply. Undefined if * Returns the reply code of the received server reply. Undefined if
* this is not a reply event. * this is not a reply event.
@ -106,8 +101,7 @@ public class ProtocolCommandEvent extends EventObject
* @return The reply code of the received server reply. Undefined if * @return The reply code of the received server reply. Undefined if
* not a reply event. * not a reply event.
***/ ***/
public int getReplyCode() public int getReplyCode() {
{
return __replyCode; return __replyCode;
} }
@ -118,8 +112,7 @@ public class ProtocolCommandEvent extends EventObject
* @return true If the ProtocolCommandEvent was generated as a result * @return true If the ProtocolCommandEvent was generated as a result
* of sending a command. False otherwise. * of sending a command. False otherwise.
***/ ***/
public boolean isCommand() public boolean isCommand() {
{
return __isCommand; return __isCommand;
} }
@ -130,8 +123,7 @@ public class ProtocolCommandEvent extends EventObject
* @return true If the ProtocolCommandEvent was generated as a result * @return true If the ProtocolCommandEvent was generated as a result
* of receiving a reply. False otherwise. * of receiving a reply. False otherwise.
***/ ***/
public boolean isReply() public boolean isReply() {
{
return !isCommand(); return !isCommand();
} }
@ -141,8 +133,7 @@ public class ProtocolCommandEvent extends EventObject
* *
* @return The entire message sent to or received from the server. * @return The entire message sent to or received from the server.
***/ ***/
public String getMessage() public String getMessage() {
{
return __message; return __message;
} }
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net; package org.apache.commons.net;
import java.util.EventListener; import java.util.EventListener;
/*** /***
@ -36,8 +37,7 @@ import java.util.EventListener;
* @see ProtocolCommandSupport * @see ProtocolCommandSupport
***/ ***/
public interface ProtocolCommandListener extends EventListener public interface ProtocolCommandListener extends EventListener {
{
/*** /***
* This method is invoked by a ProtocolCommandEvent source after * This method is invoked by a ProtocolCommandEvent source after
@ -54,5 +54,4 @@ public interface ProtocolCommandListener extends EventListener
* @param event The ProtocolCommandEvent fired. * @param event The ProtocolCommandEvent fired.
***/ ***/
public void protocolReplyReceived(ProtocolCommandEvent event); public void protocolReplyReceived(ProtocolCommandEvent event);
} }

@ -33,8 +33,7 @@ import org.apache.commons.net.util.ListenerList;
* @see ProtocolCommandListener * @see ProtocolCommandListener
***/ ***/
public class ProtocolCommandSupport implements Serializable public class ProtocolCommandSupport implements Serializable {
{
private static final long serialVersionUID = -8017692739988399978L; private static final long serialVersionUID = -8017692739988399978L;
private final Object __source; private final Object __source;
@ -46,13 +45,11 @@ public class ProtocolCommandSupport implements Serializable
* *
* @param source The source to use for all generated ProtocolCommandEvents. * @param source The source to use for all generated ProtocolCommandEvents.
***/ ***/
public ProtocolCommandSupport(Object source) public ProtocolCommandSupport(Object source) {
{
__listeners = new ListenerList(); __listeners = new ListenerList();
__source = source; __source = source;
} }
/*** /***
* Fires a ProtocolCommandEvent signalling the sending of a command to all * Fires a ProtocolCommandEvent signalling the sending of a command to all
* registered listeners, invoking their * registered listeners, invoking their
@ -64,15 +61,13 @@ public class ProtocolCommandSupport implements Serializable
* @param message The entire command string verbatim as sent to the server, * @param message The entire command string verbatim as sent to the server,
* including all arguments. * including all arguments.
***/ ***/
public void fireCommandSent(String command, String message) public void fireCommandSent(String command, String message) {
{
ProtocolCommandEvent event; ProtocolCommandEvent event;
event = new ProtocolCommandEvent(__source, command, message); event = new ProtocolCommandEvent(__source, command, message);
for (EventListener listener : __listeners) for (EventListener listener : __listeners) {
{ ((ProtocolCommandListener) listener).protocolCommandSent(event);
((ProtocolCommandListener)listener).protocolCommandSent(event);
} }
} }
@ -89,14 +84,12 @@ public class ProtocolCommandSupport implements Serializable
* strings like OK rather than integer codes (i.e., POP3Repy.OK). * strings like OK rather than integer codes (i.e., POP3Repy.OK).
* @param message The entire reply as received from the server. * @param message The entire reply as received from the server.
***/ ***/
public void fireReplyReceived(int replyCode, String message) public void fireReplyReceived(int replyCode, String message) {
{
ProtocolCommandEvent event; ProtocolCommandEvent event;
event = new ProtocolCommandEvent(__source, replyCode, message); event = new ProtocolCommandEvent(__source, replyCode, message);
for (EventListener listener : __listeners) for (EventListener listener : __listeners) {
{ ((ProtocolCommandListener) listener).protocolReplyReceived(event);
((ProtocolCommandListener)listener).protocolReplyReceived(event);
} }
} }
@ -105,8 +98,7 @@ public class ProtocolCommandSupport implements Serializable
* *
* @param listener The ProtocolCommandListener to add. * @param listener The ProtocolCommandListener to add.
***/ ***/
public void addProtocolCommandListener(ProtocolCommandListener listener) public void addProtocolCommandListener(ProtocolCommandListener listener) {
{
__listeners.addListener(listener); __listeners.addListener(listener);
} }
@ -115,21 +107,17 @@ public class ProtocolCommandSupport implements Serializable
* *
* @param listener The ProtocolCommandListener to remove. * @param listener The ProtocolCommandListener to remove.
***/ ***/
public void removeProtocolCommandListener(ProtocolCommandListener listener) public void removeProtocolCommandListener(ProtocolCommandListener listener) {
{
__listeners.removeListener(listener); __listeners.removeListener(listener);
} }
/*** /***
* Returns the number of ProtocolCommandListeners currently registered. * Returns the number of ProtocolCommandListeners currently registered.
* *
* @return The number of ProtocolCommandListeners currently registered. * @return The number of ProtocolCommandListeners currently registered.
***/ ***/
public int getListenerCount() public int getListenerCount() {
{
return __listeners.getListenerCount(); return __listeners.getListenerCount();
} }
} }

@ -31,7 +31,6 @@ import java.nio.charset.Charset;
import javax.net.ServerSocketFactory; import javax.net.ServerSocketFactory;
import javax.net.SocketFactory; import javax.net.SocketFactory;
/** /**
* The SocketClient provides the basic operations that are required of * The SocketClient provides the basic operations that are required of
* client objects accessing sockets. It is meant to be * client objects accessing sockets. It is meant to be
@ -50,10 +49,10 @@ import javax.net.SocketFactory;
* them by directly invoking a constructor. By honoring this contract * them by directly invoking a constructor. By honoring this contract
* you guarantee that a user will always be able to provide his own * you guarantee that a user will always be able to provide his own
* Socket implementations by substituting his own SocketFactory. * Socket implementations by substituting his own SocketFactory.
*
* @see SocketFactory * @see SocketFactory
*/ */
public abstract class SocketClient public abstract class SocketClient {
{
/** /**
* The end of line character sequence used by most IETF protocols. That * The end of line character sequence used by most IETF protocols. That
* is a carriage return followed by a newline: "\r\n" * is a carriage return followed by a newline: "\r\n"
@ -61,8 +60,7 @@ public abstract class SocketClient
public static final String NETASCII_EOL = "\r\n"; public static final String NETASCII_EOL = "\r\n";
/** The default SocketFactory shared by all SocketClient instances. */ /** The default SocketFactory shared by all SocketClient instances. */
private static final SocketFactory __DEFAULT_SOCKET_FACTORY = private static final SocketFactory __DEFAULT_SOCKET_FACTORY = SocketFactory.getDefault();
SocketFactory.getDefault();
/** The default {@link ServerSocketFactory} */ /** The default {@link ServerSocketFactory} */
private static final ServerSocketFactory __DEFAULT_SERVER_SOCKET_FACTORY = private static final ServerSocketFactory __DEFAULT_SERVER_SOCKET_FACTORY =
@ -123,8 +121,7 @@ public abstract class SocketClient
* and _socketFactory_ to a shared instance of * and _socketFactory_ to a shared instance of
* {@link org.apache.commons.net.DefaultSocketFactory}. * {@link org.apache.commons.net.DefaultSocketFactory}.
*/ */
public SocketClient() public SocketClient() {
{
_socket_ = null; _socket_ = null;
_hostname_ = null; _hostname_ = null;
_input_ = null; _input_ = null;
@ -135,7 +132,6 @@ public abstract class SocketClient
_serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY; _serverSocketFactory_ = __DEFAULT_SERVER_SOCKET_FACTORY;
} }
/** /**
* Because there are so many connect() methods, the _connectAction_() * Because there are so many connect() methods, the _connectAction_()
* method is provided as a means of performing some action immediately * method is provided as a means of performing some action immediately
@ -151,22 +147,22 @@ public abstract class SocketClient
* Subclasses overriding this method should start by calling * Subclasses overriding this method should start by calling
* <code> super._connectAction_() </code> first to ensure the * <code> super._connectAction_() </code> first to ensure the
* initialization of the aforementioned protected variables. * initialization of the aforementioned protected variables.
*
* @throws IOException (SocketException) if a problem occurs with the socket * @throws IOException (SocketException) if a problem occurs with the socket
*/ */
protected void _connectAction_() throws IOException protected void _connectAction_() throws IOException {
{
_socket_.setSoTimeout(_timeout_); _socket_.setSoTimeout(_timeout_);
_input_ = _socket_.getInputStream(); _input_ = _socket_.getInputStream();
_output_ = _socket_.getOutputStream(); _output_ = _socket_.getOutputStream();
} }
/** /**
* Opens a Socket connected to a remote host at the specified port and * Opens a Socket connected to a remote host at the specified port and
* originating from the current host at a system assigned port. * originating from the current host at a system assigned port.
* Before returning, {@link #_connectAction_ _connectAction_() } * Before returning, {@link #_connectAction_ _connectAction_() }
* is called to perform connection initialization actions. * is called to perform connection initialization actions.
* <p> * <p>
*
* @param host The remote host. * @param host The remote host.
* @param port The port to connect to on 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 SocketException If the socket timeout could not be set.
@ -174,9 +170,7 @@ public abstract class SocketClient
* cases you will only want to catch IOException since SocketException is * cases you will only want to catch IOException since SocketException is
* derived from it. * derived from it.
*/ */
public void connect(InetAddress host, int port) public void connect(InetAddress host, int port) throws SocketException, IOException {
throws SocketException, IOException
{
_hostname_ = null; _hostname_ = null;
_connect(host, port, null, -1); _connect(host, port, null, -1);
} }
@ -187,6 +181,7 @@ public abstract class SocketClient
* Before returning, {@link #_connectAction_ _connectAction_() } * Before returning, {@link #_connectAction_ _connectAction_() }
* is called to perform connection initialization actions. * is called to perform connection initialization actions.
* <p> * <p>
*
* @param hostname The name of the remote host. * @param hostname The name of the remote host.
* @param port The port to connect to on 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 SocketException If the socket timeout could not be set.
@ -195,20 +190,18 @@ public abstract class SocketClient
* derived from it. * derived from it.
* @throws java.net.UnknownHostException If the hostname cannot be resolved. * @throws java.net.UnknownHostException If the hostname cannot be resolved.
*/ */
public void connect(String hostname, int port) public void connect(String hostname, int port) throws SocketException, IOException {
throws SocketException, IOException
{
_hostname_ = hostname; _hostname_ = hostname;
_connect(InetAddress.getByName(hostname), port, null, -1); _connect(InetAddress.getByName(hostname), port, null, -1);
} }
/** /**
* Opens a Socket connected to a remote host at the specified port and * Opens a Socket connected to a remote host at the specified port and
* originating from the specified local address and port. * originating from the specified local address and port.
* Before returning, {@link #_connectAction_ _connectAction_() } * Before returning, {@link #_connectAction_ _connectAction_() }
* is called to perform connection initialization actions. * is called to perform connection initialization actions.
* <p> * <p>
*
* @param host The remote host. * @param host The remote host.
* @param port The port to connect to on the remote host. * @param port The port to connect to on the remote host.
* @param localAddr The local address to use. * @param localAddr The local address to use.
@ -218,18 +211,15 @@ public abstract class SocketClient
* cases you will only want to catch IOException since SocketException is * cases you will only want to catch IOException since SocketException is
* derived from it. * derived from it.
*/ */
public void connect(InetAddress host, int port, public void connect(InetAddress host, int port, InetAddress localAddr, int localPort)
InetAddress localAddr, int localPort) throws SocketException, IOException {
throws SocketException, IOException
{
_hostname_ = null; _hostname_ = null;
_connect(host, port, localAddr, localPort); _connect(host, port, localAddr, localPort);
} }
// helper method to allow code to be shared with connect(String,...) methods // helper method to allow code to be shared with connect(String,...) methods
private void _connect(InetAddress host, int port, InetAddress localAddr, int localPort) private void _connect(InetAddress host, int port, InetAddress localAddr, int localPort)
throws SocketException, IOException throws SocketException, IOException {
{
_socket_ = _socketFactory_.createSocket(); _socket_ = _socketFactory_.createSocket();
if (receiveBufferSize != -1) { if (receiveBufferSize != -1) {
_socket_.setReceiveBufferSize(receiveBufferSize); _socket_.setReceiveBufferSize(receiveBufferSize);
@ -250,6 +240,7 @@ public abstract class SocketClient
* Before returning, {@link #_connectAction_ _connectAction_() } * Before returning, {@link #_connectAction_ _connectAction_() }
* is called to perform connection initialization actions. * is called to perform connection initialization actions.
* <p> * <p>
*
* @param hostname The name of the remote host. * @param hostname The name of the remote host.
* @param port The port to connect to on the remote host. * @param port The port to connect to on the remote host.
* @param localAddr The local address to use. * @param localAddr The local address to use.
@ -260,40 +251,37 @@ public abstract class SocketClient
* derived from it. * derived from it.
* @throws java.net.UnknownHostException If the hostname cannot be resolved. * @throws java.net.UnknownHostException If the hostname cannot be resolved.
*/ */
public void connect(String hostname, int port, public void connect(String hostname, int port, InetAddress localAddr, int localPort)
InetAddress localAddr, int localPort) throws SocketException, IOException {
throws SocketException, IOException
{
_hostname_ = hostname; _hostname_ = hostname;
_connect(InetAddress.getByName(hostname), port, localAddr, localPort); _connect(InetAddress.getByName(hostname), port, localAddr, localPort);
} }
/** /**
* Opens a Socket connected to a remote host at the current default port * Opens a Socket connected to a remote host at the current default port
* and originating from the current host at a system assigned port. * and originating from the current host at a system assigned port.
* Before returning, {@link #_connectAction_ _connectAction_() } * Before returning, {@link #_connectAction_ _connectAction_() }
* is called to perform connection initialization actions. * is called to perform connection initialization actions.
* <p> * <p>
*
* @param host The remote host. * @param host The remote host.
* @throws SocketException If the socket timeout could not be set. * @throws SocketException If the socket timeout could not be set.
* @throws IOException If the socket could not be opened. In most * @throws IOException If the socket could not be opened. In most
* cases you will only want to catch IOException since SocketException is * cases you will only want to catch IOException since SocketException is
* derived from it. * derived from it.
*/ */
public void connect(InetAddress host) throws SocketException, IOException public void connect(InetAddress host) throws SocketException, IOException {
{
_hostname_ = null; _hostname_ = null;
connect(host, _defaultPort_); connect(host, _defaultPort_);
} }
/** /**
* Opens a Socket connected to a remote host at the current default * Opens a Socket connected to a remote host at the current default
* port and originating from the current host at a system assigned port. * port and originating from the current host at a system assigned port.
* Before returning, {@link #_connectAction_ _connectAction_() } * Before returning, {@link #_connectAction_ _connectAction_() }
* is called to perform connection initialization actions. * is called to perform connection initialization actions.
* <p> * <p>
*
* @param hostname The name of the remote host. * @param hostname The name of the remote host.
* @throws SocketException If the socket timeout could not be set. * @throws SocketException If the socket timeout could not be set.
* @throws IOException If the socket could not be opened. In most * @throws IOException If the socket could not be opened. In most
@ -301,12 +289,10 @@ public abstract class SocketClient
* derived from it. * derived from it.
* @throws java.net.UnknownHostException If the hostname cannot be resolved. * @throws java.net.UnknownHostException If the hostname cannot be resolved.
*/ */
public void connect(String hostname) throws SocketException, IOException public void connect(String hostname) throws SocketException, IOException {
{
connect(hostname, _defaultPort_); connect(hostname, _defaultPort_);
} }
/** /**
* Disconnects the socket connection. * Disconnects the socket connection.
* You should call this method after you've finished using the class * You should call this method after you've finished using the class
@ -315,10 +301,10 @@ public abstract class SocketClient
* again. _isConnected_ is set to false, _socket_ is set to null, * again. _isConnected_ is set to false, _socket_ is set to null,
* _input_ is set to null, and _output_ is set to null. * _input_ is set to null, and _output_ is set to null.
* <p> * <p>
*
* @throws IOException If there is an error closing the socket. * @throws IOException If there is an error closing the socket.
*/ */
public void disconnect() throws IOException public void disconnect() throws IOException {
{
closeQuietly(_socket_); closeQuietly(_socket_);
closeQuietly(_input_); closeQuietly(_input_);
closeQuietly(_output_); closeQuietly(_output_);
@ -329,7 +315,7 @@ public abstract class SocketClient
} }
private void closeQuietly(Socket socket) { private void closeQuietly(Socket socket) {
if (socket != null){ if (socket != null) {
try { try {
socket.close(); socket.close();
} catch (IOException e) { } catch (IOException e) {
@ -338,8 +324,8 @@ public abstract class SocketClient
} }
} }
private void closeQuietly(Closeable close){ private void closeQuietly(Closeable close) {
if (close != null){ if (close != null) {
try { try {
close.close(); close.close();
} catch (IOException e) { } catch (IOException e) {
@ -347,15 +333,16 @@ public abstract class SocketClient
} }
} }
} }
/** /**
* Returns true if the client is currently connected to a server. * Returns true if the client is currently connected to a server.
* <p> * <p>
* Delegates to {@link Socket#isConnected()} * Delegates to {@link Socket#isConnected()}
*
* @return True if the client is currently connected to a server, * @return True if the client is currently connected to a server,
* false otherwise. * false otherwise.
*/ */
public boolean isConnected() public boolean isConnected() {
{
if (_socket_ == null) { if (_socket_ == null) {
return false; return false;
} }
@ -367,14 +354,14 @@ public abstract class SocketClient
* Make various checks on the socket to test if it is available for use. * 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 * Note that the only sure test is to use it, but these checks may help
* in some cases. * in some cases.
* @see <a href="https://issues.apache.org/jira/browse/NET-350">NET-350</a> *
* @return {@code true} if the socket appears to be available for use * @return {@code true} if the socket appears to be available for use
* @see <a href="https://issues.apache.org/jira/browse/NET-350">NET-350</a>
* @since 3.0 * @since 3.0
*/ */
public boolean isAvailable(){ public boolean isAvailable() {
if (isConnected()) { if (isConnected()) {
try try {
{
if (_socket_.getInetAddress() == null) { if (_socket_.getInetAddress() == null) {
return false; return false;
} }
@ -399,9 +386,7 @@ public abstract class SocketClient
/* ignore the result, catch exceptions: */ /* ignore the result, catch exceptions: */
_socket_.getInputStream(); _socket_.getInputStream();
_socket_.getOutputStream(); _socket_.getOutputStream();
} } catch (IOException ioex) {
catch (IOException ioex)
{
return false; return false;
} }
return true; return true;
@ -416,10 +401,10 @@ public abstract class SocketClient
* variable stores this value. If never set, the default port is equal * variable stores this value. If never set, the default port is equal
* to zero. * to zero.
* <p> * <p>
*
* @param port The default port to set. * @param port The default port to set.
*/ */
public void setDefaultPort(int port) public void setDefaultPort(int port) {
{
_defaultPort_ = port; _defaultPort_ = port;
} }
@ -427,14 +412,13 @@ public abstract class SocketClient
* Returns the current value of the default port (stored in * Returns the current value of the default port (stored in
* {@link #_defaultPort_ _defaultPort_ }). * {@link #_defaultPort_ _defaultPort_ }).
* <p> * <p>
*
* @return The current value of the default port. * @return The current value of the default port.
*/ */
public int getDefaultPort() public int getDefaultPort() {
{
return _defaultPort_; return _defaultPort_;
} }
/** /**
* Set the default timeout in milliseconds to use when opening a socket. * Set the default timeout in milliseconds to use when opening a socket.
* This value is only used previous to a call to * This value is only used previous to a call to
@ -443,28 +427,26 @@ public abstract class SocketClient
* which operates on an the currently opened socket. _timeout_ contains * which operates on an the currently opened socket. _timeout_ contains
* the new timeout value. * the new timeout value.
* <p> * <p>
*
* @param timeout The timeout in milliseconds to use for the socket * @param timeout The timeout in milliseconds to use for the socket
* connection. * connection.
*/ */
public void setDefaultTimeout(int timeout) public void setDefaultTimeout(int timeout) {
{
_timeout_ = timeout; _timeout_ = timeout;
} }
/** /**
* Returns the default timeout in milliseconds that is used when * Returns the default timeout in milliseconds that is used when
* opening a socket. * opening a socket.
* <p> * <p>
*
* @return The default timeout in milliseconds that is used when * @return The default timeout in milliseconds that is used when
* opening a socket. * opening a socket.
*/ */
public int getDefaultTimeout() public int getDefaultTimeout() {
{
return _timeout_; return _timeout_;
} }
/** /**
* Set the timeout in milliseconds of a currently open connection. * Set the timeout in milliseconds of a currently open connection.
* Only call this method after a connection has been opened * Only call this method after a connection has been opened
@ -477,15 +459,14 @@ public abstract class SocketClient
* @throws SocketException If the operation fails. * @throws SocketException If the operation fails.
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public void setSoTimeout(int timeout) throws SocketException public void setSoTimeout(int timeout) throws SocketException {
{
_socket_.setSoTimeout(timeout); _socket_.setSoTimeout(timeout);
} }
/** /**
* Set the underlying socket send buffer size. * Set the underlying socket send buffer size.
* <p> * <p>
*
* @param size The size of the buffer in bytes. * @param size The size of the buffer in bytes.
* @throws SocketException never thrown, but subclasses might want to do so * @throws SocketException never thrown, but subclasses might want to do so
* @since 2.0 * @since 2.0
@ -496,16 +477,18 @@ public abstract class SocketClient
/** /**
* Get the current sendBuffer size * Get the current sendBuffer size
*
* @return the size, or -1 if not initialised * @return the size, or -1 if not initialised
* @since 3.0 * @since 3.0
*/ */
protected int getSendBufferSize(){ protected int getSendBufferSize() {
return sendBufferSize; return sendBufferSize;
} }
/** /**
* Sets the underlying socket receive buffer size. * Sets the underlying socket receive buffer size.
* <p> * <p>
*
* @param size The size of the buffer in bytes. * @param size The size of the buffer in bytes.
* @throws SocketException never (but subclasses may wish to do so) * @throws SocketException never (but subclasses may wish to do so)
* @since 2.0 * @since 2.0
@ -516,22 +499,23 @@ public abstract class SocketClient
/** /**
* Get the current receivedBuffer size * Get the current receivedBuffer size
*
* @return the size, or -1 if not initialised * @return the size, or -1 if not initialised
* @since 3.0 * @since 3.0
*/ */
protected int getReceiveBufferSize(){ protected int getReceiveBufferSize() {
return receiveBufferSize; return receiveBufferSize;
} }
/** /**
* Returns the timeout in milliseconds of the currently opened socket. * Returns the timeout in milliseconds of the currently opened socket.
* <p> * <p>
*
* @return 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 SocketException If the operation fails.
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public int getSoTimeout() throws SocketException public int getSoTimeout() throws SocketException {
{
return _socket_.getSoTimeout(); return _socket_.getSoTimeout();
} }
@ -539,27 +523,26 @@ public abstract class SocketClient
* Enables or disables the Nagle's algorithm (TCP_NODELAY) on the * Enables or disables the Nagle's algorithm (TCP_NODELAY) on the
* currently opened socket. * currently opened socket.
* <p> * <p>
*
* @param on True if Nagle's algorithm is to be enabled, false if not. * @param on True if Nagle's algorithm is to be enabled, false if not.
* @throws SocketException If the operation fails. * @throws SocketException If the operation fails.
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public void setTcpNoDelay(boolean on) throws SocketException public void setTcpNoDelay(boolean on) throws SocketException {
{
_socket_.setTcpNoDelay(on); _socket_.setTcpNoDelay(on);
} }
/** /**
* Returns true if Nagle's algorithm is enabled on the currently opened * Returns true if Nagle's algorithm is enabled on the currently opened
* socket. * socket.
* <p> * <p>
*
* @return True if Nagle's algorithm is enabled on the currently opened * @return True if Nagle's algorithm is enabled on the currently opened
* socket, false otherwise. * socket, false otherwise.
* @throws SocketException If the operation fails. * @throws SocketException If the operation fails.
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public boolean getTcpNoDelay() throws SocketException public boolean getTcpNoDelay() throws SocketException {
{
return _socket_.getTcpNoDelay(); return _socket_.getTcpNoDelay();
} }
@ -570,6 +553,7 @@ public abstract class SocketClient
* implementation dependent). It looks as though the Windows WSA sockets implementation * 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 * allows a specific keepalive value to be set, although this seems not to be the case on
* other systems. * other systems.
*
* @param keepAlive If true, keepAlive is turned on * @param keepAlive If true, keepAlive is turned on
* @throws SocketException if there is a problem with the socket * @throws SocketException if there is a problem with the socket
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
@ -582,6 +566,7 @@ public abstract class SocketClient
/** /**
* Returns the current value of the SO_KEEPALIVE flag on the currently opened socket. * Returns the current value of the SO_KEEPALIVE flag on the currently opened socket.
* Delegates to {@link Socket#getKeepAlive()} * Delegates to {@link Socket#getKeepAlive()}
*
* @return True if SO_KEEPALIVE is enabled. * @return True if SO_KEEPALIVE is enabled.
* @throws SocketException if there is a problem with the socket * @throws SocketException if there is a problem with the socket
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
@ -594,55 +579,52 @@ public abstract class SocketClient
/** /**
* Sets the SO_LINGER timeout on the currently opened socket. * Sets the SO_LINGER timeout on the currently opened socket.
* <p> * <p>
*
* @param on True if linger is to be enabled, false if not. * @param on True if linger is to be enabled, false if not.
* @param val The linger timeout (in hundredths of a second?) * @param val The linger timeout (in hundredths of a second?)
* @throws SocketException If the operation fails. * @throws SocketException If the operation fails.
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public void setSoLinger(boolean on, int val) throws SocketException public void setSoLinger(boolean on, int val) throws SocketException {
{
_socket_.setSoLinger(on, val); _socket_.setSoLinger(on, val);
} }
/** /**
* Returns the current SO_LINGER timeout of the currently opened socket. * Returns the current SO_LINGER timeout of the currently opened socket.
* <p> * <p>
*
* @return The current SO_LINGER timeout. If SO_LINGER is disabled returns * @return The current SO_LINGER timeout. If SO_LINGER is disabled returns
* -1. * -1.
* @throws SocketException If the operation fails. * @throws SocketException If the operation fails.
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public int getSoLinger() throws SocketException public int getSoLinger() throws SocketException {
{
return _socket_.getSoLinger(); return _socket_.getSoLinger();
} }
/** /**
* Returns the port number of the open socket on the local host used * Returns the port number of the open socket on the local host used
* for the connection. * for the connection.
* Delegates to {@link Socket#getLocalPort()} * Delegates to {@link Socket#getLocalPort()}
* <p> * <p>
*
* @return The port number of the open socket on the local host used * @return The port number of the open socket on the local host used
* for the connection. * for the connection.
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public int getLocalPort() public int getLocalPort() {
{
return _socket_.getLocalPort(); return _socket_.getLocalPort();
} }
/** /**
* Returns the local address to which the client's socket is bound. * Returns the local address to which the client's socket is bound.
* Delegates to {@link Socket#getLocalAddress()} * Delegates to {@link Socket#getLocalAddress()}
* <p> * <p>
*
* @return The local address to which the client's socket is bound. * @return The local address to which the client's socket is bound.
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public InetAddress getLocalAddress() public InetAddress getLocalAddress() {
{
return _socket_.getLocalAddress(); return _socket_.getLocalAddress();
} }
@ -651,27 +633,24 @@ public abstract class SocketClient
* connected. * connected.
* Delegates to {@link Socket#getPort()} * Delegates to {@link Socket#getPort()}
* <p> * <p>
*
* @return The port number of the remote host to which the client is * @return The port number of the remote host to which the client is
* connected. * connected.
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public int getRemotePort() public int getRemotePort() {
{
return _socket_.getPort(); return _socket_.getPort();
} }
/** /**
* @return The remote address to which the client is connected. * @return The remote address to which the client is connected.
* Delegates to {@link Socket#getInetAddress()} * Delegates to {@link Socket#getInetAddress()}
* @throws NullPointerException if the socket is not currently open * @throws NullPointerException if the socket is not currently open
*/ */
public InetAddress getRemoteAddress() public InetAddress getRemoteAddress() {
{
return _socket_.getInetAddress(); return _socket_.getInetAddress();
} }
/** /**
* Verifies that the remote end of the given socket is connected to the * Verifies that the remote end of the given socket is connected to the
* the same host that the SocketClient is currently connected to. This * the same host that the SocketClient is currently connected to. This
@ -679,11 +658,11 @@ public abstract class SocketClient
* accept a connection from a server, such as an FTP data connection or * accept a connection from a server, such as an FTP data connection or
* a BSD R command standard error stream. * a BSD R command standard error stream.
* <p> * <p>
*
* @param socket the item to check against * @param socket the item to check against
* @return True if the remote hosts are the same, false if not. * @return True if the remote hosts are the same, false if not.
*/ */
public boolean verifyRemote(Socket socket) public boolean verifyRemote(Socket socket) {
{
InetAddress host1, host2; InetAddress host1, host2;
host1 = socket.getInetAddress(); host1 = socket.getInetAddress();
@ -692,7 +671,6 @@ public abstract class SocketClient
return host1.equals(host2); return host1.equals(host2);
} }
/** /**
* Sets the SocketFactory used by the SocketClient to open socket * Sets the SocketFactory used by the SocketClient to open socket
* connections. If the factory value is null, then a default * connections. If the factory value is null, then a default
@ -700,10 +678,10 @@ public abstract class SocketClient
* previously altered it). * previously altered it).
* Any proxy setting is discarded. * Any proxy setting is discarded.
* <p> * <p>
*
* @param factory The new SocketFactory the SocketClient should use. * @param factory The new SocketFactory the SocketClient should use.
*/ */
public void setSocketFactory(SocketFactory factory) public void setSocketFactory(SocketFactory factory) {
{
if (factory == null) { if (factory == null) {
_socketFactory_ = __DEFAULT_SOCKET_FACTORY; _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
} else { } else {
@ -721,6 +699,7 @@ public abstract class SocketClient
* factory is used (only do this to reset the factory after having * factory is used (only do this to reset the factory after having
* previously altered it). * previously altered it).
* <p> * <p>
*
* @param factory The new ServerSocketFactory the SocketClient should use. * @param factory The new ServerSocketFactory the SocketClient should use.
* @since 2.0 * @since 2.0
*/ */
@ -733,8 +712,10 @@ public abstract class SocketClient
} }
/** /**
* Sets the connection timeout in milliseconds, which will be passed to the {@link Socket} object's * Sets the connection timeout in milliseconds, which will be passed to the {@link Socket}
* object's
* connect() method. * connect() method.
*
* @param connectTimeout The connection timeout to use (in ms) * @param connectTimeout The connection timeout to use (in ms)
* @since 2.0 * @since 2.0
*/ */
@ -744,6 +725,7 @@ public abstract class SocketClient
/** /**
* Get the underlying socket connection timeout. * Get the underlying socket connection timeout.
*
* @return timeout (in ms) * @return timeout (in ms)
* @since 2.0 * @since 2.0
*/ */
@ -753,6 +735,7 @@ public abstract class SocketClient
/** /**
* Get the underlying {@link ServerSocketFactory} * Get the underlying {@link ServerSocketFactory}
*
* @return The server socket factory * @return The server socket factory
* @since 2.2 * @since 2.2
*/ */
@ -760,7 +743,6 @@ public abstract class SocketClient
return _serverSocketFactory_; return _serverSocketFactory_;
} }
/** /**
* Adds a ProtocolCommandListener. * Adds a ProtocolCommandListener.
* *
@ -810,7 +792,7 @@ public abstract class SocketClient
/** /**
* Create the CommandSupport instance if required * Create the CommandSupport instance if required
*/ */
protected void createCommandSupport(){ protected void createCommandSupport() {
__commandSupport = new ProtocolCommandSupport(this); __commandSupport = new ProtocolCommandSupport(this);
} }
@ -840,6 +822,7 @@ public abstract class SocketClient
/** /**
* Gets the proxy for use with all the connections. * Gets the proxy for use with all the connections.
*
* @return the current proxy for connections. * @return the current proxy for connections.
*/ */
public Proxy getProxy() { public Proxy getProxy() {
@ -853,8 +836,7 @@ public abstract class SocketClient
* @since 3.3 * @since 3.3
* @deprecated Since the code now requires Java 1.6 as a mininmum * @deprecated Since the code now requires Java 1.6 as a mininmum
*/ */
@Deprecated @Deprecated public String getCharsetName() {
public String getCharsetName() {
return charset.name(); return charset.name();
} }

@ -17,7 +17,6 @@
package org.apache.commons.net.ftp; package org.apache.commons.net.ftp;
/** /**
* This interface adds the aspect of configurability by means of * This interface adds the aspect of configurability by means of
* a supplied FTPClientConfig object to other classes in the * a supplied FTPClientConfig object to other classes in the

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp; package org.apache.commons.net.ftp;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.IOException; import java.io.IOException;
@ -92,8 +93,7 @@ import org.apache.commons.net.io.CRLFLineReader;
* @version $Id: FTP.java 1782546 2017-02-11 00:05:41Z sebb $ * @version $Id: FTP.java 1782546 2017-02-11 00:05:41Z sebb $
***/ ***/
public class FTP extends SocketClient public class FTP extends SocketClient {
{
/*** The default FTP data port (20). ***/ /*** The default FTP data port (20). ***/
public static final int DEFAULT_DATA_PORT = 20; public static final int DEFAULT_DATA_PORT = 20;
/*** The default FTP control port (21). ***/ /*** The default FTP control port (21). ***/
@ -114,7 +114,6 @@ public class FTP extends SocketClient
***/ ***/
public static final int EBCDIC_FILE_TYPE = 1; public static final int EBCDIC_FILE_TYPE = 1;
/*** /***
* A constant used to indicate the file(s) being transferred should * A constant used to indicate the file(s) being transferred should
* be treated as a binary image, i.e., no translations should be * be treated as a binary image, i.e., no translations should be
@ -266,8 +265,7 @@ public class FTP extends SocketClient
* <code>DEFAULT_PORT</code> and initializes internal data structures * <code>DEFAULT_PORT</code> and initializes internal data structures
* for saving FTP reply information. * for saving FTP reply information.
***/ ***/
public FTP() public FTP() {
{
super(); super();
setDefaultPort(DEFAULT_PORT); setDefaultPort(DEFAULT_PORT);
_replyLines = new ArrayList<String>(); _replyLines = new ArrayList<String>();
@ -288,31 +286,30 @@ public class FTP extends SocketClient
// test that the line starts with a digit rather than starting with // test that the line starts with a digit rather than starting with
// the code. // the code.
private boolean __lenientCheck(String line) { private boolean __lenientCheck(String line) {
return (!(line.length() > REPLY_CODE_LEN&& line.charAt(REPLY_CODE_LEN) != '-' && return (!(line.length() > REPLY_CODE_LEN
Character.isDigit(line.charAt(0)))); && line.charAt(REPLY_CODE_LEN) != '-'
&& Character.isDigit(line.charAt(0))));
} }
/** /**
* Get the reply, and pass it to command listeners * Get the reply, and pass it to command listeners
*/ */
private void __getReply() throws IOException private void __getReply() throws IOException {
{
__getReply(true); __getReply(true);
} }
/** /**
* Get the reply, but don't pass it to command listeners. * Get the reply, but don't pass it to command listeners.
* Used for keep-alive processing only. * Used for keep-alive processing only.
* @since 3.0 *
* @throws IOException on error * @throws IOException on error
* @since 3.0
*/ */
protected void __getReplyNoReport() throws IOException protected void __getReplyNoReport() throws IOException {
{
__getReply(false); __getReply(false);
} }
private void __getReply(boolean reportReply) throws IOException private void __getReply(boolean reportReply) throws IOException {
{
int length; int length;
_newReplyString = true; _newReplyString = true;
@ -321,26 +318,21 @@ public class FTP extends SocketClient
String line = _controlInput_.readLine(); String line = _controlInput_.readLine();
if (line == null) { if (line == null) {
throw new FTPConnectionClosedException( throw new FTPConnectionClosedException("Connection closed without indication.");
"Connection closed without indication.");
} }
// In case we run into an anomaly we don't want fatal index exceptions // In case we run into an anomaly we don't want fatal index exceptions
// to be thrown. // to be thrown.
length = line.length(); length = line.length();
if (length < REPLY_CODE_LEN) { if (length < REPLY_CODE_LEN) {
throw new MalformedServerReplyException( throw new MalformedServerReplyException("Truncated server reply: " + line);
"Truncated server reply: " + line);
} }
String code = null; String code = null;
try try {
{
code = line.substring(0, REPLY_CODE_LEN); code = line.substring(0, REPLY_CODE_LEN);
_replyCode = Integer.parseInt(code); _replyCode = Integer.parseInt(code);
} } catch (NumberFormatException e) {
catch (NumberFormatException e)
{
throw new MalformedServerReplyException( throw new MalformedServerReplyException(
"Could not parse response code.\nServer Reply: " + line); "Could not parse response code.\nServer Reply: " + line);
} }
@ -352,13 +344,11 @@ public class FTP extends SocketClient
char sep = line.charAt(REPLY_CODE_LEN); char sep = line.charAt(REPLY_CODE_LEN);
// Get extra lines if message continues. // Get extra lines if message continues.
if (sep == '-') { if (sep == '-') {
do do {
{
line = _controlInput_.readLine(); line = _controlInput_.readLine();
if (line == null) { if (line == null) {
throw new FTPConnectionClosedException( throw new FTPConnectionClosedException("Connection closed without indication.");
"Connection closed without indication.");
} }
_replyLines.add(line); _replyLines.add(line);
@ -366,18 +356,16 @@ public class FTP extends SocketClient
// The length() check handles problems that could arise from readLine() // The length() check handles problems that could arise from readLine()
// returning too soon after encountering a naked CR or some other // returning too soon after encountering a naked CR or some other
// anomaly. // anomaly.
} } while (isStrictMultilineParsing() ? __strictCheck(line, code) : __lenientCheck(line));
while ( isStrictMultilineParsing() ? __strictCheck(line, code) : __lenientCheck(line));
} else if (isStrictReplyParsing()) { } else if (isStrictReplyParsing()) {
if (length == REPLY_CODE_LEN + 1) { // expecting some text if (length == REPLY_CODE_LEN + 1) { // expecting some text
throw new MalformedServerReplyException("Truncated server reply: '" + line +"'"); throw new MalformedServerReplyException("Truncated server reply: '" + line + "'");
} else if (sep != ' ') { } else if (sep != ' ') {
throw new MalformedServerReplyException("Invalid server reply: '" + line +"'"); throw new MalformedServerReplyException("Invalid server reply: '" + line + "'");
} }
} }
} else if (isStrictReplyParsing()) { } else if (isStrictReplyParsing()) {
throw new MalformedServerReplyException("Truncated server reply: '" + line +"'"); throw new MalformedServerReplyException("Truncated server reply: '" + line + "'");
} }
if (reportReply) { if (reportReply) {
@ -385,7 +373,8 @@ public class FTP extends SocketClient
} }
if (_replyCode == FTPReply.SERVICE_NOT_AVAILABLE) { if (_replyCode == FTPReply.SERVICE_NOT_AVAILABLE) {
throw new FTPConnectionClosedException("FTP response 421 received. Server closed connection."); throw new FTPConnectionClosedException(
"FTP response 421 received. Server closed connection.");
} }
} }
@ -393,13 +382,10 @@ public class FTP extends SocketClient
* Initiates control connections and gets initial reply. * Initiates control connections and gets initial reply.
* Initializes {@link #_controlInput_} and {@link #_controlOutput_}. * Initializes {@link #_controlInput_} and {@link #_controlOutput_}.
*/ */
@Override @Override protected void _connectAction_() throws IOException {
protected void _connectAction_() throws IOException
{
_connectAction_(null); _connectAction_(null);
} }
/** /**
* Initiates control connections and gets initial reply. * Initiates control connections and gets initial reply.
* Initializes {@link #_controlInput_} and {@link #_controlOutput_}. * Initializes {@link #_controlInput_} and {@link #_controlOutput_}.
@ -410,14 +396,12 @@ public class FTP extends SocketClient
*/ */
protected void _connectAction_(Reader socketIsReader) throws IOException { protected void _connectAction_(Reader socketIsReader) throws IOException {
super._connectAction_(); // sets up _input_ and _output_ super._connectAction_(); // sets up _input_ and _output_
if(socketIsReader == null) { if (socketIsReader == null) {
_controlInput_ = _controlInput_ = new CRLFLineReader(new InputStreamReader(_input_, getControlEncoding()));
new CRLFLineReader(new InputStreamReader(_input_, getControlEncoding()));
} else { } else {
_controlInput_ = new CRLFLineReader(socketIsReader); _controlInput_ = new CRLFLineReader(socketIsReader);
} }
_controlOutput_ = _controlOutput_ = new BufferedWriter(new OutputStreamWriter(_output_, getControlEncoding()));
new BufferedWriter(new OutputStreamWriter(_output_, getControlEncoding()));
if (connectTimeout > 0) { // NET-385 if (connectTimeout > 0) { // NET-385
int original = _socket_.getSoTimeout(); int original = _socket_.getSoTimeout();
_socket_.setSoTimeout(connectTimeout); _socket_.setSoTimeout(connectTimeout);
@ -443,7 +427,6 @@ public class FTP extends SocketClient
} }
} }
/** /**
* Saves the character encoding to be used by the FTP control connection. * Saves the character encoding to be used by the FTP control connection.
* Some FTP servers require that commands be issued in a non-ASCII * Some FTP servers require that commands be issued in a non-ASCII
@ -458,7 +441,6 @@ public class FTP extends SocketClient
_controlEncoding = encoding; _controlEncoding = encoding;
} }
/** /**
* @return The character encoding used to communicate over the * @return The character encoding used to communicate over the
* control connection. * control connection.
@ -467,7 +449,6 @@ public class FTP extends SocketClient
return _controlEncoding; return _controlEncoding;
} }
/*** /***
* Closes the control connection to the FTP server and sets to null * Closes the control connection to the FTP server and sets to null
* some internal data so that the memory may be reclaimed by the * some internal data so that the memory may be reclaimed by the
@ -477,9 +458,7 @@ public class FTP extends SocketClient
* *
* @throws IOException If an error occurs while disconnecting. * @throws IOException If an error occurs while disconnecting.
***/ ***/
@Override @Override public void disconnect() throws IOException {
public void disconnect() throws IOException
{
super.disconnect(); super.disconnect();
_controlInput_ = null; _controlInput_ = null;
_controlOutput_ = null; _controlOutput_ = null;
@ -487,7 +466,6 @@ public class FTP extends SocketClient
_replyString = null; _replyString = null;
} }
/*** /***
* Sends an FTP command to the server, waits for a reply and returns the * Sends an FTP command to the server, waits for a reply and returns the
* numerical response code. After invocation, for more detailed * numerical response code. After invocation, for more detailed
@ -508,8 +486,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int sendCommand(String command, String args) throws IOException public int sendCommand(String command, String args) throws IOException {
{
if (_controlOutput_ == null) { if (_controlOutput_ == null) {
throw new IOException("Connection is not open"); throw new IOException("Connection is not open");
} }
@ -529,8 +506,7 @@ public class FTP extends SocketClient
__commandBuffer.append(command); __commandBuffer.append(command);
if (args != null) if (args != null) {
{
__commandBuffer.append(' '); __commandBuffer.append(' ');
__commandBuffer.append(args); __commandBuffer.append(args);
} }
@ -538,20 +514,15 @@ public class FTP extends SocketClient
return __commandBuffer.toString(); return __commandBuffer.toString();
} }
private void __send(String message) throws IOException, private void __send(String message)
FTPConnectionClosedException, SocketException { throws IOException, FTPConnectionClosedException, SocketException {
try{ try {
_controlOutput_.write(message); _controlOutput_.write(message);
_controlOutput_.flush(); _controlOutput_.flush();
} } catch (SocketException e) {
catch (SocketException e) if (!isConnected()) {
{
if (!isConnected())
{
throw new FTPConnectionClosedException("Connection unexpectedly closed."); throw new FTPConnectionClosedException("Connection unexpectedly closed.");
} } else {
else
{
throw e; throw e;
} }
} }
@ -592,9 +563,7 @@ public class FTP extends SocketClient
* command or receiving the server reply. * command or receiving the server reply.
* @deprecated (3.3) Use {@link #sendCommand(FTPCmd, String)} instead * @deprecated (3.3) Use {@link #sendCommand(FTPCmd, String)} instead
***/ ***/
@Deprecated @Deprecated public int sendCommand(int command, String args) throws IOException {
public int sendCommand(int command, String args) throws IOException
{
return sendCommand(FTPCommand.getCommand(command), args); return sendCommand(FTPCommand.getCommand(command), args);
} }
@ -609,8 +578,8 @@ public class FTP extends SocketClient
* to send. * to send.
* @return The integer value of the FTP reply code returned by the server * @return The integer value of the FTP reply code returned by the server
* in response to the command. * in response to the command.
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
@ -618,7 +587,7 @@ public class FTP extends SocketClient
* command or receiving the server reply. * command or receiving the server reply.
* @since 3.3 * @since 3.3
*/ */
public int sendCommand(FTPCmd command) throws IOException{ public int sendCommand(FTPCmd command) throws IOException {
return sendCommand(command, null); return sendCommand(command, null);
} }
@ -635,8 +604,8 @@ public class FTP extends SocketClient
* set to null, then the command is sent with no argument. * set to null, then the command is sent with no argument.
* @return The integer value of the FTP reply code returned by the server * @return The integer value of the FTP reply code returned by the server
* in response to the command. * in response to the command.
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
@ -644,7 +613,7 @@ public class FTP extends SocketClient
* command or receiving the server reply. * command or receiving the server reply.
* @since 3.3 * @since 3.3
*/ */
public int sendCommand(FTPCmd command, String args) throws IOException{ public int sendCommand(FTPCmd command, String args) throws IOException {
return sendCommand(command.getCommand(), args); return sendCommand(command.getCommand(), args);
} }
@ -666,12 +635,10 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int sendCommand(String command) throws IOException public int sendCommand(String command) throws IOException {
{
return sendCommand(command, null); return sendCommand(command, null);
} }
/*** /***
* Sends an FTP command with no arguments to the server, waits for a * Sends an FTP command with no arguments to the server, waits for a
* reply and returns the numerical response code. After invocation, for * reply and returns the numerical response code. After invocation, for
@ -691,12 +658,10 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int sendCommand(int command) throws IOException public int sendCommand(int command) throws IOException {
{
return sendCommand(command, null); return sendCommand(command, null);
} }
/*** /***
* Returns the integer value of the reply code of the last FTP reply. * 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 * You will usually only use this method after you connect to the
@ -705,8 +670,7 @@ public class FTP extends SocketClient
* *
* @return The integer value of the reply code of the last FTP reply. * @return The integer value of the reply code of the last FTP reply.
***/ ***/
public int getReplyCode() public int getReplyCode() {
{
return _replyCode; return _replyCode;
} }
@ -727,13 +691,11 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while receiving the * @throws IOException If an I/O error occurs while receiving the
* server reply. * server reply.
***/ ***/
public int getReply() throws IOException public int getReply() throws IOException {
{
__getReply(); __getReply();
return _replyCode; return _replyCode;
} }
/*** /***
* Returns the lines of text from the last FTP server response as an array * 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 * of strings, one entry per line. The end of line markers of each are
@ -741,8 +703,7 @@ public class FTP extends SocketClient
* *
* @return The lines of text from the last FTP response as an array. * @return The lines of text from the last FTP response as an array.
***/ ***/
public String[] getReplyStrings() public String[] getReplyStrings() {
{
return _replyLines.toArray(new String[_replyLines.size()]); return _replyLines.toArray(new String[_replyLines.size()]);
} }
@ -753,8 +714,7 @@ public class FTP extends SocketClient
* *
* @return The entire text from the last FTP response as a String. * @return The entire text from the last FTP response as a String.
***/ ***/
public String getReplyString() public String getReplyString() {
{
StringBuilder buffer; StringBuilder buffer;
if (!_newReplyString) { if (!_newReplyString) {
@ -773,7 +733,6 @@ public class FTP extends SocketClient
return (_replyString = buffer.toString()); return (_replyString = buffer.toString());
} }
/*** /***
* A convenience method to send the FTP USER command to the server, * A convenience method to send the FTP USER command to the server,
* receive the reply, and return the reply code. * receive the reply, and return the reply code.
@ -788,26 +747,25 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int user(String username) throws IOException public int user(String username) throws IOException {
{
return sendCommand(FTPCmd.USER, username); return sendCommand(FTPCmd.USER, username);
} }
/** /**
* A convenience method to send the FTP PASS command to the server, * A convenience method to send the FTP PASS command to the server,
* receive the reply, and return the reply code. * receive the reply, and return the reply code.
*
* @param password The plain text password of the username being logged into. * @param password The plain text password of the username being logged into.
* @return The reply code received from the server. * @return The reply code received from the server.
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
*/ */
public int pass(String password) throws IOException public int pass(String password) throws IOException {
{
return sendCommand(FTPCmd.PASS, password); return sendCommand(FTPCmd.PASS, password);
} }
@ -825,12 +783,10 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int acct(String account) throws IOException public int acct(String account) throws IOException {
{
return sendCommand(FTPCmd.ACCT, account); return sendCommand(FTPCmd.ACCT, account);
} }
/*** /***
* A convenience method to send the FTP ABOR command to the server, * A convenience method to send the FTP ABOR command to the server,
* receive the reply, and return the reply code. * receive the reply, and return the reply code.
@ -844,8 +800,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int abor() throws IOException public int abor() throws IOException {
{
return sendCommand(FTPCmd.ABOR); return sendCommand(FTPCmd.ABOR);
} }
@ -863,8 +818,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int cwd(String directory) throws IOException public int cwd(String directory) throws IOException {
{
return sendCommand(FTPCmd.CWD, directory); return sendCommand(FTPCmd.CWD, directory);
} }
@ -881,8 +835,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int cdup() throws IOException public int cdup() throws IOException {
{
return sendCommand(FTPCmd.CDUP); return sendCommand(FTPCmd.CDUP);
} }
@ -899,8 +852,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int quit() throws IOException public int quit() throws IOException {
{
return sendCommand(FTPCmd.QUIT); return sendCommand(FTPCmd.QUIT);
} }
@ -917,8 +869,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int rein() throws IOException public int rein() throws IOException {
{
return sendCommand(FTPCmd.REIN); return sendCommand(FTPCmd.REIN);
} }
@ -936,8 +887,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int smnt(String dir) throws IOException public int smnt(String dir) throws IOException {
{
return sendCommand(FTPCmd.SMNT, dir); return sendCommand(FTPCmd.SMNT, dir);
} }
@ -956,8 +906,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int port(InetAddress host, int port) throws IOException public int port(InetAddress host, int port) throws IOException {
{
int num; int num;
StringBuilder info = new StringBuilder(24); StringBuilder info = new StringBuilder(24);
@ -996,8 +945,7 @@ public class FTP extends SocketClient
* command or receiving the server reply. * command or receiving the server reply.
* @since 2.2 * @since 2.2
***/ ***/
public int eprt(InetAddress host, int port) throws IOException public int eprt(InetAddress host, int port) throws IOException {
{
int num; int num;
StringBuilder info = new StringBuilder(); StringBuilder info = new StringBuilder();
String h; String h;
@ -1040,8 +988,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int pasv() throws IOException public int pasv() throws IOException {
{
return sendCommand(FTPCmd.PASV); return sendCommand(FTPCmd.PASV);
} }
@ -1061,30 +1008,29 @@ public class FTP extends SocketClient
* command or receiving the server reply. * command or receiving the server reply.
* @since 2.2 * @since 2.2
***/ ***/
public int epsv() throws IOException public int epsv() throws IOException {
{
return sendCommand(FTPCmd.EPSV); return sendCommand(FTPCmd.EPSV);
} }
/** /**
* A convenience method to send the FTP TYPE command for text files * A convenience method to send the FTP TYPE command for text files
* to the server, receive the reply, and return the reply code. * to the server, receive the reply, and return the reply code.
*
* @param fileType The type of the file (one of the <code>FILE_TYPE</code> * @param fileType The type of the file (one of the <code>FILE_TYPE</code>
* constants). * constants).
* @param formatOrByteSize The format of the file (one of the * @param formatOrByteSize The format of the file (one of the
* <code>_FORMAT</code> constants. In the case of * <code>_FORMAT</code> constants. In the case of
* <code>LOCAL_FILE_TYPE</code>, the byte size. * <code>LOCAL_FILE_TYPE</code>, the byte size.
* @return The reply code received from the server. * @return The reply code received from the server.
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
*/ */
public int type(int fileType, int formatOrByteSize) throws IOException public int type(int fileType, int formatOrByteSize) throws IOException {
{
StringBuilder arg = new StringBuilder(); StringBuilder arg = new StringBuilder();
arg.append(__modes.charAt(fileType)); arg.append(__modes.charAt(fileType));
@ -1098,7 +1044,6 @@ public class FTP extends SocketClient
return sendCommand(FTPCmd.TYPE, arg.toString()); return sendCommand(FTPCmd.TYPE, arg.toString());
} }
/** /**
* A convenience method to send the FTP TYPE command to the server, * A convenience method to send the FTP TYPE command to the server,
* receive the reply, and return the reply code. * receive the reply, and return the reply code.
@ -1106,18 +1051,16 @@ public class FTP extends SocketClient
* @param fileType The type of the file (one of the <code>FILE_TYPE</code> * @param fileType The type of the file (one of the <code>FILE_TYPE</code>
* constants). * constants).
* @return The reply code received from the server. * @return The reply code received from the server.
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
*/ */
public int type(int fileType) throws IOException public int type(int fileType) throws IOException {
{ return sendCommand(FTPCmd.TYPE, __modes.substring(fileType, fileType + 1));
return sendCommand(FTPCmd.TYPE,
__modes.substring(fileType, fileType + 1));
} }
/*** /***
@ -1135,10 +1078,8 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int stru(int structure) throws IOException public int stru(int structure) throws IOException {
{ return sendCommand(FTPCmd.STRU, __modes.substring(structure, structure + 1));
return sendCommand(FTPCmd.STRU,
__modes.substring(structure, structure + 1));
} }
/*** /***
@ -1156,10 +1097,8 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int mode(int mode) throws IOException public int mode(int mode) throws IOException {
{ return sendCommand(FTPCmd.MODE, __modes.substring(mode, mode + 1));
return sendCommand(FTPCmd.MODE,
__modes.substring(mode, mode + 1));
} }
/*** /***
@ -1179,8 +1118,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int retr(String pathname) throws IOException public int retr(String pathname) throws IOException {
{
return sendCommand(FTPCmd.RETR, pathname); return sendCommand(FTPCmd.RETR, pathname);
} }
@ -1202,8 +1140,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int stor(String pathname) throws IOException public int stor(String pathname) throws IOException {
{
return sendCommand(FTPCmd.STOR, pathname); return sendCommand(FTPCmd.STOR, pathname);
} }
@ -1223,8 +1160,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int stou() throws IOException public int stou() throws IOException {
{
return sendCommand(FTPCmd.STOU); return sendCommand(FTPCmd.STOU);
} }
@ -1246,8 +1182,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
*/ */
public int stou(String pathname) throws IOException public int stou(String pathname) throws IOException {
{
return sendCommand(FTPCmd.STOU, pathname); return sendCommand(FTPCmd.STOU, pathname);
} }
@ -1269,8 +1204,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int appe(String pathname) throws IOException public int appe(String pathname) throws IOException {
{
return sendCommand(FTPCmd.APPE, pathname); return sendCommand(FTPCmd.APPE, pathname);
} }
@ -1288,21 +1222,20 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int allo(int bytes) throws IOException public int allo(int bytes) throws IOException {
{
return sendCommand(FTPCmd.ALLO, Integer.toString(bytes)); return sendCommand(FTPCmd.ALLO, Integer.toString(bytes));
} }
/** /**
* A convenience method to send the FTP FEAT command to the server, receive the reply, * A convenience method to send the FTP FEAT command to the server, receive the reply,
* and return the reply code. * and return the reply code.
*
* @return The reply code received by the server * @return The reply code received by the server
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
* @since 2.2 * @since 2.2
*/ */
public int feat() throws IOException public int feat() throws IOException {
{
return sendCommand(FTPCmd.FEAT); return sendCommand(FTPCmd.FEAT);
} }
@ -1321,10 +1254,8 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int allo(int bytes, int recordSize) throws IOException public int allo(int bytes, int recordSize) throws IOException {
{ return sendCommand(FTPCmd.ALLO, Integer.toString(bytes) + " R " + Integer.toString(recordSize));
return sendCommand(FTPCmd.ALLO, Integer.toString(bytes) + " R " +
Integer.toString(recordSize));
} }
/*** /***
@ -1341,24 +1272,20 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int rest(String marker) throws IOException public int rest(String marker) throws IOException {
{
return sendCommand(FTPCmd.REST, marker); return sendCommand(FTPCmd.REST, marker);
} }
/** /**
* @param file name of file * @param file name of file
* @return the status * @return the status
* @throws IOException on error * @throws IOException on error
* @since 2.0 * @since 2.0
**/ **/
public int mdtm(String file) throws IOException public int mdtm(String file) throws IOException {
{
return sendCommand(FTPCmd.MDTM, file); return sendCommand(FTPCmd.MDTM, file);
} }
/** /**
* A convenience method to send the FTP MFMT command to the server, * A convenience method to send the FTP MFMT command to the server,
* receive the reply, and return the reply code. * receive the reply, and return the reply code.
@ -1366,22 +1293,20 @@ public class FTP extends SocketClient
* @param pathname The pathname for which mtime is to be changed * @param pathname The pathname for which mtime is to be changed
* @param timeval Timestamp in <code>YYYYMMDDhhmmss</code> format * @param timeval Timestamp in <code>YYYYMMDDhhmmss</code> format
* @return The reply code received from the server. * @return The reply code received from the server.
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
* @since 2.2
* @see <a href="http://tools.ietf.org/html/draft-somers-ftp-mfxx-04">http://tools.ietf.org/html/draft-somers-ftp-mfxx-04</a> * @see <a href="http://tools.ietf.org/html/draft-somers-ftp-mfxx-04">http://tools.ietf.org/html/draft-somers-ftp-mfxx-04</a>
* @since 2.2
**/ **/
public int mfmt(String pathname, String timeval) throws IOException public int mfmt(String pathname, String timeval) throws IOException {
{
return sendCommand(FTPCmd.MFMT, timeval + " " + pathname); return sendCommand(FTPCmd.MFMT, timeval + " " + pathname);
} }
/*** /***
* A convenience method to send the FTP RNFR command to the server, * A convenience method to send the FTP RNFR command to the server,
* receive the reply, and return the reply code. * receive the reply, and return the reply code.
@ -1396,8 +1321,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int rnfr(String pathname) throws IOException public int rnfr(String pathname) throws IOException {
{
return sendCommand(FTPCmd.RNFR, pathname); return sendCommand(FTPCmd.RNFR, pathname);
} }
@ -1415,8 +1339,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int rnto(String pathname) throws IOException public int rnto(String pathname) throws IOException {
{
return sendCommand(FTPCmd.RNTO, pathname); return sendCommand(FTPCmd.RNTO, pathname);
} }
@ -1434,8 +1357,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int dele(String pathname) throws IOException public int dele(String pathname) throws IOException {
{
return sendCommand(FTPCmd.DELE, pathname); return sendCommand(FTPCmd.DELE, pathname);
} }
@ -1453,8 +1375,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int rmd(String pathname) throws IOException public int rmd(String pathname) throws IOException {
{
return sendCommand(FTPCmd.RMD, pathname); return sendCommand(FTPCmd.RMD, pathname);
} }
@ -1472,8 +1393,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int mkd(String pathname) throws IOException public int mkd(String pathname) throws IOException {
{
return sendCommand(FTPCmd.MKD, pathname); return sendCommand(FTPCmd.MKD, pathname);
} }
@ -1490,8 +1410,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int pwd() throws IOException public int pwd() throws IOException {
{
return sendCommand(FTPCmd.PWD); return sendCommand(FTPCmd.PWD);
} }
@ -1511,8 +1430,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int list() throws IOException public int list() throws IOException {
{
return sendCommand(FTPCmd.LIST); return sendCommand(FTPCmd.LIST);
} }
@ -1534,8 +1452,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int list(String pathname) throws IOException public int list(String pathname) throws IOException {
{
return sendCommand(FTPCmd.LIST, pathname); return sendCommand(FTPCmd.LIST, pathname);
} }
@ -1547,8 +1464,8 @@ public class FTP extends SocketClient
* , which will handle all low level details for you. * , which will handle all low level details for you.
* *
* @return The reply code received from the server. * @return The reply code received from the server.
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
@ -1556,8 +1473,7 @@ public class FTP extends SocketClient
* command or receiving the server reply. * command or receiving the server reply.
* @since 3.0 * @since 3.0
*/ */
public int mlsd() throws IOException public int mlsd() throws IOException {
{
return sendCommand(FTPCmd.MLSD); return sendCommand(FTPCmd.MLSD);
} }
@ -1571,8 +1487,8 @@ public class FTP extends SocketClient
* @param path the path to report on * @param path the path to report on
* @return The reply code received from the server, * @return The reply code received from the server,
* may be {@code null} in which case the command is sent with no parameters * may be {@code null} in which case the command is sent with no parameters
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
@ -1580,8 +1496,7 @@ public class FTP extends SocketClient
* command or receiving the server reply. * command or receiving the server reply.
* @since 3.0 * @since 3.0
*/ */
public int mlsd(String path) throws IOException public int mlsd(String path) throws IOException {
{
return sendCommand(FTPCmd.MLSD, path); return sendCommand(FTPCmd.MLSD, path);
} }
@ -1593,8 +1508,8 @@ public class FTP extends SocketClient
* , which will handle all low level details for you. * , which will handle all low level details for you.
* *
* @return The reply code received from the server. * @return The reply code received from the server.
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
@ -1602,8 +1517,7 @@ public class FTP extends SocketClient
* command or receiving the server reply. * command or receiving the server reply.
* @since 3.0 * @since 3.0
*/ */
public int mlst() throws IOException public int mlst() throws IOException {
{
return sendCommand(FTPCmd.MLST); return sendCommand(FTPCmd.MLST);
} }
@ -1617,8 +1531,8 @@ public class FTP extends SocketClient
* @param path the path to report on * @param path the path to report on
* @return The reply code received from the server, * @return The reply code received from the server,
* may be {@code null} in which case the command is sent with no parameters * may be {@code null} in which case the command is sent with no parameters
* @throws FTPConnectionClosedException * @throws FTPConnectionClosedException If the FTP server prematurely closes the connection as a
* If the FTP server prematurely closes the connection as a result * result
* of the client being idle or some other reason causing the server * of the client being idle or some other reason causing the server
* to send FTP reply code 421. This exception may be caught either * to send FTP reply code 421. This exception may be caught either
* as an IOException or independently as itself. * as an IOException or independently as itself.
@ -1626,8 +1540,7 @@ public class FTP extends SocketClient
* command or receiving the server reply. * command or receiving the server reply.
* @since 3.0 * @since 3.0
*/ */
public int mlst(String path) throws IOException public int mlst(String path) throws IOException {
{
return sendCommand(FTPCmd.MLST, path); return sendCommand(FTPCmd.MLST, path);
} }
@ -1647,8 +1560,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int nlst() throws IOException public int nlst() throws IOException {
{
return sendCommand(FTPCmd.NLST); return sendCommand(FTPCmd.NLST);
} }
@ -1670,8 +1582,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int nlst(String pathname) throws IOException public int nlst(String pathname) throws IOException {
{
return sendCommand(FTPCmd.NLST, pathname); return sendCommand(FTPCmd.NLST, pathname);
} }
@ -1689,8 +1600,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int site(String parameters) throws IOException public int site(String parameters) throws IOException {
{
return sendCommand(FTPCmd.SITE, parameters); return sendCommand(FTPCmd.SITE, parameters);
} }
@ -1707,8 +1617,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int syst() throws IOException public int syst() throws IOException {
{
return sendCommand(FTPCmd.SYST); return sendCommand(FTPCmd.SYST);
} }
@ -1725,8 +1634,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int stat() throws IOException public int stat() throws IOException {
{
return sendCommand(FTPCmd.STAT); return sendCommand(FTPCmd.STAT);
} }
@ -1744,8 +1652,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int stat(String pathname) throws IOException public int stat(String pathname) throws IOException {
{
return sendCommand(FTPCmd.STAT, pathname); return sendCommand(FTPCmd.STAT, pathname);
} }
@ -1762,8 +1669,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int help() throws IOException public int help() throws IOException {
{
return sendCommand(FTPCmd.HELP); return sendCommand(FTPCmd.HELP);
} }
@ -1781,8 +1687,7 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int help(String command) throws IOException public int help(String command) throws IOException {
{
return sendCommand(FTPCmd.HELP, command); return sendCommand(FTPCmd.HELP, command);
} }
@ -1799,13 +1704,13 @@ public class FTP extends SocketClient
* @throws IOException If an I/O error occurs while either sending the * @throws IOException If an I/O error occurs while either sending the
* command or receiving the server reply. * command or receiving the server reply.
***/ ***/
public int noop() throws IOException public int noop() throws IOException {
{
return sendCommand(FTPCmd.NOOP); return sendCommand(FTPCmd.NOOP);
} }
/** /**
* Return whether strict multiline parsing is enabled, as per RFC 959, section 4.2. * Return whether strict multiline parsing is enabled, as per RFC 959, section 4.2.
*
* @return True if strict, false if lenient * @return True if strict, false if lenient
* @since 2.0 * @since 2.0
*/ */
@ -1815,6 +1720,7 @@ public class FTP extends SocketClient
/** /**
* Set strict multiline parsing. * Set strict multiline parsing.
*
* @param strictMultilineParsing the setting * @param strictMultilineParsing the setting
* @since 2.0 * @since 2.0
*/ */
@ -1829,6 +1735,7 @@ public class FTP extends SocketClient
* <br> * <br>
* If false, only the 3 digit code is required (as was the case for versions up to 3.5) * If false, only the 3 digit code is required (as was the case for versions up to 3.5)
* <br> * <br>
*
* @return True if strict (default), false if additional checks are not made * @return True if strict (default), false if additional checks are not made
* @since 3.6 * @since 3.6
*/ */
@ -1845,6 +1752,7 @@ public class FTP extends SocketClient
* <p> * <p>
* <b>This should not be required by a well-behaved FTP server</b> * <b>This should not be required by a well-behaved FTP server</b>
* <br> * <br>
*
* @param strictReplyParsing the setting * @param strictReplyParsing the setting
* @since 3.6 * @since 3.6
*/ */
@ -1855,8 +1763,7 @@ public class FTP extends SocketClient
/** /**
* Provide command support to super-class * Provide command support to super-class
*/ */
@Override @Override protected ProtocolCommandSupport getCommandSupport() {
protected ProtocolCommandSupport getCommandSupport() {
return _commandSupport_; return _commandSupport_;
} }
} }

@ -129,14 +129,13 @@ import java.util.TreeMap;
* FTPFile[] files = listFiles(directory); * FTPFile[] files = listFiles(directory);
* </pre> * </pre>
* *
* @since 1.4
* @see Configurable * @see Configurable
* @see FTPClient * @see FTPClient
* @see org.apache.commons.net.ftp.parser.FTPTimestampParserImpl#configure(FTPClientConfig) * @see org.apache.commons.net.ftp.parser.FTPTimestampParserImpl#configure(FTPClientConfig)
* @see org.apache.commons.net.ftp.parser.ConfigurableFTPFileEntryParserImpl * @see org.apache.commons.net.ftp.parser.ConfigurableFTPFileEntryParserImpl
* @since 1.4
*/ */
public class FTPClientConfig public class FTPClientConfig {
{
/** /**
* Identifier by which a unix-based ftp server is known throughout * Identifier by which a unix-based ftp server is known throughout
@ -149,6 +148,7 @@ public class FTPClientConfig
* trimmed from file names. This is to maintain backwards compatibility with * trimmed from file names. This is to maintain backwards compatibility with
* the original behaviour of the parser which ignored multiple spaces between the date * the original behaviour of the parser which ignored multiple spaces between the date
* and the start of the file name. * and the start of the file name.
*
* @since 3.4 * @since 3.4
*/ */
public static final String SYST_UNIX_TRIM_LEADING = "UNIX_LTRIM"; public static final String SYST_UNIX_TRIM_LEADING = "UNIX_LTRIM";
@ -228,9 +228,9 @@ public class FTPClientConfig
private String serverTimeZoneId = null; private String serverTimeZoneId = null;
private boolean saveUnparseableEntries = false; private boolean saveUnparseableEntries = false;
/** /**
* The main constructor for an FTPClientConfig object * The main constructor for an FTPClientConfig object
*
* @param systemKey key representing system type of the server being * @param systemKey key representing system type of the server being
* connected to. See {@link #getServerSystemKey() serverSystemKey} * connected to. See {@link #getServerSystemKey() serverSystemKey}
* If set to the empty string, then FTPClient uses the system type returned by the server. * If set to the empty string, then FTPClient uses the system type returned by the server.
@ -251,6 +251,7 @@ public class FTPClientConfig
/** /**
* Constructor which allows setting of the format string member fields * Constructor which allows setting of the format string member fields
*
* @param systemKey key representing system type of the server being * @param systemKey key representing system type of the server being
* connected to. See * connected to. See
* {@link #getServerSystemKey() serverSystemKey} * {@link #getServerSystemKey() serverSystemKey}
@ -260,10 +261,8 @@ public class FTPClientConfig
* {@link #setRecentDateFormatStr(String) recentDateFormatStr} * {@link #setRecentDateFormatStr(String) recentDateFormatStr}
* @since 3.6 * @since 3.6
*/ */
public FTPClientConfig(String systemKey, public FTPClientConfig(String systemKey, String defaultDateFormatStr,
String defaultDateFormatStr, String recentDateFormatStr) {
String recentDateFormatStr)
{
this(systemKey); this(systemKey);
this.defaultDateFormatStr = defaultDateFormatStr; this.defaultDateFormatStr = defaultDateFormatStr;
this.recentDateFormatStr = recentDateFormatStr; this.recentDateFormatStr = recentDateFormatStr;
@ -271,6 +270,7 @@ public class FTPClientConfig
/** /**
* Constructor which allows setting of most member fields * Constructor which allows setting of most member fields
*
* @param systemKey key representing system type of the server being * @param systemKey key representing system type of the server being
* connected to. See * connected to. See
* {@link #getServerSystemKey() serverSystemKey} * {@link #getServerSystemKey() serverSystemKey}
@ -285,13 +285,8 @@ public class FTPClientConfig
* @param serverTimeZoneId See * @param serverTimeZoneId See
* {@link #setServerTimeZoneId(String) serverTimeZoneId} * {@link #setServerTimeZoneId(String) serverTimeZoneId}
*/ */
public FTPClientConfig(String systemKey, public FTPClientConfig(String systemKey, String defaultDateFormatStr, String recentDateFormatStr,
String defaultDateFormatStr, String serverLanguageCode, String shortMonthNames, String serverTimeZoneId) {
String recentDateFormatStr,
String serverLanguageCode,
String shortMonthNames,
String serverTimeZoneId)
{
this(systemKey); this(systemKey);
this.defaultDateFormatStr = defaultDateFormatStr; this.defaultDateFormatStr = defaultDateFormatStr;
this.recentDateFormatStr = recentDateFormatStr; this.recentDateFormatStr = recentDateFormatStr;
@ -302,6 +297,7 @@ public class FTPClientConfig
/** /**
* Constructor which allows setting of all member fields * Constructor which allows setting of all member fields
*
* @param systemKey key representing system type of the server being * @param systemKey key representing system type of the server being
* connected to. See * connected to. See
* {@link #getServerSystemKey() serverSystemKey} * {@link #getServerSystemKey() serverSystemKey}
@ -320,15 +316,9 @@ public class FTPClientConfig
* @param saveUnparseableEntries See * @param saveUnparseableEntries See
* {@link #setUnparseableEntries(boolean) saveUnparseableEntries} * {@link #setUnparseableEntries(boolean) saveUnparseableEntries}
*/ */
public FTPClientConfig(String systemKey, public FTPClientConfig(String systemKey, String defaultDateFormatStr, String recentDateFormatStr,
String defaultDateFormatStr, String serverLanguageCode, String shortMonthNames, String serverTimeZoneId,
String recentDateFormatStr, boolean lenientFutureDates, boolean saveUnparseableEntries) {
String serverLanguageCode,
String shortMonthNames,
String serverTimeZoneId,
boolean lenientFutureDates,
boolean saveUnparseableEntries)
{
this(systemKey); this(systemKey);
this.defaultDateFormatStr = defaultDateFormatStr; this.defaultDateFormatStr = defaultDateFormatStr;
this.lenientFutureDates = lenientFutureDates; this.lenientFutureDates = lenientFutureDates;
@ -353,6 +343,7 @@ public class FTPClientConfig
/** /**
* Copy constructor * Copy constructor
*
* @param config source * @param config source
* @since 3.6 * @since 3.6
*/ */
@ -368,18 +359,17 @@ public class FTPClientConfig
} }
private static final Map<String, Object> LANGUAGE_CODE_MAP = new TreeMap<String, Object>(); private static final Map<String, Object> LANGUAGE_CODE_MAP = new TreeMap<String, Object>();
static { static {
// if there are other commonly used month name encodings which // if there are other commonly used month name encodings which
// correspond to particular locales, please add them here. // correspond to particular locales, please add them here.
// many locales code short names for months as all three letters // many locales code short names for months as all three letters
// these we handle simply. // these we handle simply.
LANGUAGE_CODE_MAP.put("en", Locale.ENGLISH); LANGUAGE_CODE_MAP.put("en", Locale.ENGLISH);
LANGUAGE_CODE_MAP.put("de",Locale.GERMAN); LANGUAGE_CODE_MAP.put("de", Locale.GERMAN);
LANGUAGE_CODE_MAP.put("it",Locale.ITALIAN); LANGUAGE_CODE_MAP.put("it", Locale.ITALIAN);
LANGUAGE_CODE_MAP.put("es", new Locale("es", "", "")); // spanish LANGUAGE_CODE_MAP.put("es", new Locale("es", "", "")); // spanish
LANGUAGE_CODE_MAP.put("pt", new Locale("pt", "", "")); // portuguese LANGUAGE_CODE_MAP.put("pt", new Locale("pt", "", "")); // portuguese
LANGUAGE_CODE_MAP.put("da", new Locale("da", "", "")); // danish LANGUAGE_CODE_MAP.put("da", new Locale("da", "", "")); // danish
@ -392,11 +382,9 @@ public class FTPClientConfig
LANGUAGE_CODE_MAP.put("sk", new Locale("sk", "", "")); // slovak LANGUAGE_CODE_MAP.put("sk", new Locale("sk", "", "")); // slovak
LANGUAGE_CODE_MAP.put("sl", new Locale("sl", "", "")); // slovenian LANGUAGE_CODE_MAP.put("sl", new Locale("sl", "", "")); // slovenian
// some don't // some don't
LANGUAGE_CODE_MAP.put("fr", LANGUAGE_CODE_MAP.put("fr",
"jan|f\u00e9v|mar|avr|mai|jun|jui|ao\u00fb|sep|oct|nov|d\u00e9c"); //french "jan|f\u00e9v|mar|avr|mai|jun|jui|ao\u00fb|sep|oct|nov|d\u00e9c"); //french
} }
/** /**
@ -406,6 +394,7 @@ public class FTPClientConfig
* or else the fully qualified class name of a parser implementing both * or else the fully qualified class name of a parser implementing both
* the <code>FTPFileEntryParser</code> and <code>Configurable</code> * the <code>FTPFileEntryParser</code> and <code>Configurable</code>
* interfaces. * interfaces.
*
* @return Returns the serverSystemKey property. * @return Returns the serverSystemKey property.
*/ */
public String getServerSystemKey() { public String getServerSystemKey() {
@ -415,6 +404,7 @@ public class FTPClientConfig
/** /**
* getter for the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} * getter for the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr}
* property. * property.
*
* @return Returns the defaultDateFormatStr property. * @return Returns the defaultDateFormatStr property.
*/ */
public String getDefaultDateFormatStr() { public String getDefaultDateFormatStr() {
@ -423,6 +413,7 @@ public class FTPClientConfig
/** /**
* getter for the {@link #setRecentDateFormatStr(String) recentDateFormatStr} property. * getter for the {@link #setRecentDateFormatStr(String) recentDateFormatStr} property.
*
* @return Returns the recentDateFormatStr property. * @return Returns the recentDateFormatStr property.
*/ */
@ -432,6 +423,7 @@ public class FTPClientConfig
/** /**
* getter for the {@link #setServerTimeZoneId(String) serverTimeZoneId} property. * getter for the {@link #setServerTimeZoneId(String) serverTimeZoneId} property.
*
* @return Returns the serverTimeZoneId property. * @return Returns the serverTimeZoneId property.
*/ */
public String getServerTimeZoneId() { public String getServerTimeZoneId() {
@ -443,6 +435,7 @@ public class FTPClientConfig
* getter for the {@link #setShortMonthNames(String) shortMonthNames} * getter for the {@link #setShortMonthNames(String) shortMonthNames}
* property. * property.
* </p> * </p>
*
* @return Returns the shortMonthNames. * @return Returns the shortMonthNames.
*/ */
public String getShortMonthNames() { public String getShortMonthNames() {
@ -453,6 +446,7 @@ public class FTPClientConfig
* <p> * <p>
* getter for the {@link #setServerLanguageCode(String) serverLanguageCode} property. * getter for the {@link #setServerLanguageCode(String) serverLanguageCode} property.
* </p> * </p>
*
* @return Returns the serverLanguageCode property. * @return Returns the serverLanguageCode property.
*/ */
public String getServerLanguageCode() { public String getServerLanguageCode() {
@ -463,12 +457,14 @@ public class FTPClientConfig
* <p> * <p>
* getter for the {@link #setLenientFutureDates(boolean) lenientFutureDates} property. * getter for the {@link #setLenientFutureDates(boolean) lenientFutureDates} property.
* </p> * </p>
*
* @return Returns the lenientFutureDates. * @return Returns the lenientFutureDates.
* @since 1.5 * @since 1.5
*/ */
public boolean isLenientFutureDates() { public boolean isLenientFutureDates() {
return lenientFutureDates; return lenientFutureDates;
} }
/** /**
* <p> * <p>
* setter for the defaultDateFormatStr property. This property * setter for the defaultDateFormatStr property. This property
@ -481,6 +477,7 @@ public class FTPClientConfig
* <code>java.text.SimpleDateFormat</code>. * <code>java.text.SimpleDateFormat</code>.
* property. * property.
* </p> * </p>
*
* @param defaultDateFormatStr The defaultDateFormatStr to set. * @param defaultDateFormatStr The defaultDateFormatStr to set.
*/ */
public void setDefaultDateFormatStr(String defaultDateFormatStr) { public void setDefaultDateFormatStr(String defaultDateFormatStr) {
@ -502,6 +499,7 @@ public class FTPClientConfig
* This should be in the format described for * This should be in the format described for
* <code>java.text.SimpleDateFormat</code>. * <code>java.text.SimpleDateFormat</code>.
* </p> * </p>
*
* @param recentDateFormatStr The recentDateFormatStr to set. * @param recentDateFormatStr The recentDateFormatStr to set.
*/ */
public void setRecentDateFormatStr(String recentDateFormatStr) { public void setRecentDateFormatStr(String recentDateFormatStr) {
@ -525,12 +523,14 @@ public class FTPClientConfig
* </p><p> * </p><p>
* This is used primarily in unix-based systems. * This is used primarily in unix-based systems.
* </p> * </p>
*
* @param lenientFutureDates set true to compensate for out-of-synch * @param lenientFutureDates set true to compensate for out-of-synch
* conditions. * conditions.
*/ */
public void setLenientFutureDates(boolean lenientFutureDates) { public void setLenientFutureDates(boolean lenientFutureDates) {
this.lenientFutureDates = lenientFutureDates; this.lenientFutureDates = lenientFutureDates;
} }
/** /**
* <p> * <p>
* setter for the serverTimeZoneId property. This property * setter for the serverTimeZoneId property. This property
@ -543,6 +543,7 @@ public class FTPClientConfig
* <code>java.util.TimeZone</code> to refer to time zones, for example, * <code>java.util.TimeZone</code> to refer to time zones, for example,
* <code>America/Chicago</code> or <code>Asia/Rangoon</code>. * <code>America/Chicago</code> or <code>Asia/Rangoon</code>.
* </p> * </p>
*
* @param serverTimeZoneId The serverTimeZoneId to set. * @param serverTimeZoneId The serverTimeZoneId to set.
*/ */
public void setServerTimeZoneId(String serverTimeZoneId) { public void setServerTimeZoneId(String serverTimeZoneId) {
@ -564,6 +565,7 @@ public class FTPClientConfig
* conceivably be specified as * conceivably be specified as
* <code>"jan|feb|mar|apr|ma&#xED;|j&#xFA;n|j&#xFA;l|&#xE1;g&#xFA;|sep|okt|n&#xF3;v|des"</code>. * <code>"jan|feb|mar|apr|ma&#xED;|j&#xFA;n|j&#xFA;l|&#xE1;g&#xFA;|sep|okt|n&#xF3;v|des"</code>.
* </p> * </p>
*
* @param shortMonthNames The value to set to the shortMonthNames property. * @param shortMonthNames The value to set to the shortMonthNames property.
*/ */
public void setShortMonthNames(String shortMonthNames) { public void setShortMonthNames(String shortMonthNames) {
@ -608,6 +610,7 @@ public class FTPClientConfig
* via the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} and/or * via the {@link #setDefaultDateFormatStr(String) defaultDateFormatStr} and/or
* {@link #setRecentDateFormatStr(String) recentDateFormatStr} parameters. * {@link #setRecentDateFormatStr(String) recentDateFormatStr} parameters.
* </p> * </p>
*
* @param serverLanguageCode The value to set to the serverLanguageCode property. * @param serverLanguageCode The value to set to the serverLanguageCode property.
*/ */
public void setServerLanguageCode(String serverLanguageCode) { public void setServerLanguageCode(String serverLanguageCode) {
@ -620,19 +623,19 @@ public class FTPClientConfig
* short month names corresponding to the code. If there is no corresponding * short month names corresponding to the code. If there is no corresponding
* entry in the table, the object returned will be that for * entry in the table, the object returned will be that for
* <code>Locale.US</code> * <code>Locale.US</code>
*
* @param languageCode See {@link #setServerLanguageCode(String) serverLanguageCode} * @param languageCode See {@link #setServerLanguageCode(String) serverLanguageCode}
* @return a DateFormatSymbols object configured with short month names * @return a DateFormatSymbols object configured with short month names
* corresponding to the supplied code, or with month names for * corresponding to the supplied code, or with month names for
* <code>Locale.US</code> if there is no corresponding entry in the internal * <code>Locale.US</code> if there is no corresponding entry in the internal
* table. * table.
*/ */
public static DateFormatSymbols lookupDateFormatSymbols(String languageCode) public static DateFormatSymbols lookupDateFormatSymbols(String languageCode) {
{
Object lang = LANGUAGE_CODE_MAP.get(languageCode); Object lang = LANGUAGE_CODE_MAP.get(languageCode);
if (lang != null) { if (lang != null) {
if (lang instanceof Locale) { if (lang instanceof Locale) {
return new DateFormatSymbols((Locale) lang); return new DateFormatSymbols((Locale) lang);
} else if (lang instanceof String){ } else if (lang instanceof String) {
return getDateFormatSymbols((String) lang); return getDateFormatSymbols((String) lang);
} }
} }
@ -642,13 +645,13 @@ public class FTPClientConfig
/** /**
* Returns a DateFormatSymbols object configured with short month names * Returns a DateFormatSymbols object configured with short month names
* as in the supplied string * as in the supplied string
*
* @param shortmonths This should be as described in * @param shortmonths This should be as described in
* {@link #setShortMonthNames(String) shortMonthNames} * {@link #setShortMonthNames(String) shortMonthNames}
* @return a DateFormatSymbols object configured with short month names * @return a DateFormatSymbols object configured with short month names
* as in the supplied string * as in the supplied string
*/ */
public static DateFormatSymbols getDateFormatSymbols(String shortmonths) public static DateFormatSymbols getDateFormatSymbols(String shortmonths) {
{
String[] months = splitShortMonthString(shortmonths); String[] months = splitShortMonthString(shortmonths);
DateFormatSymbols dfs = new DateFormatSymbols(Locale.US); DateFormatSymbols dfs = new DateFormatSymbols(Locale.US);
dfs.setShortMonths(months); dfs.setShortMonths(months);
@ -659,15 +662,14 @@ public class FTPClientConfig
StringTokenizer st = new StringTokenizer(shortmonths, "|"); StringTokenizer st = new StringTokenizer(shortmonths, "|");
int monthcnt = st.countTokens(); int monthcnt = st.countTokens();
if (12 != monthcnt) { if (12 != monthcnt) {
throw new IllegalArgumentException( throw new IllegalArgumentException("expecting a pipe-delimited string containing 12 tokens");
"expecting a pipe-delimited string containing 12 tokens");
} }
String[] months = new String[13]; String[] months = new String[13];
int pos = 0; int pos = 0;
while(st.hasMoreTokens()) { while (st.hasMoreTokens()) {
months[pos++] = st.nextToken(); months[pos++] = st.nextToken();
} }
months[pos]=""; months[pos] = "";
return months; return months;
} }
@ -688,6 +690,7 @@ public class FTPClientConfig
* <p> * <p>
* In this case, the FTPFile will contain only the unparsed entry {@link FTPFile#getRawListing()} * In this case, the FTPFile will contain only the unparsed entry {@link FTPFile#getRawListing()}
* and {@link FTPFile#isValid()} will return {@code false} * and {@link FTPFile#isValid()} will return {@code false}
*
* @param saveUnparseable if true, then create FTPFile entries if parsing fails * @param saveUnparseable if true, then create FTPFile entries if parsing fails
* @since 3.4 * @since 3.4
*/ */
@ -705,5 +708,4 @@ public class FTPClientConfig
public boolean getUnparseableEntries() { public boolean getUnparseableEntries() {
return this.saveUnparseableEntries; return this.saveUnparseableEntries;
} }
} }

@ -19,50 +19,10 @@
package org.apache.commons.net.ftp; package org.apache.commons.net.ftp;
/** /**
* @since 3.3 * @since 3.3
*/ */
public enum FTPCmd { public enum FTPCmd {
ABOR, 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,;
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 // Aliases
@ -108,8 +68,7 @@ public enum FTPCmd {
* @return The FTP protcol command string corresponding to a specified * @return The FTP protcol command string corresponding to a specified
* command code. * command code.
*/ */
public final String getCommand() public final String getCommand() {
{
return this.name(); return this.name();
} }

@ -27,9 +27,7 @@ package org.apache.commons.net.ftp;
* *
* @deprecated use {@link FTPCmd} instead * @deprecated use {@link FTPCmd} instead
*/ */
@Deprecated @Deprecated public final class FTPCommand {
public final class FTPCommand
{
public static final int USER = 0; public static final int USER = 0;
public static final int PASS = 1; public static final int PASS = 1;
@ -77,12 +75,14 @@ public final class FTPCommand
/** /**
* Machine parseable list for a directory * Machine parseable list for a directory
*
* @since 3.0 * @since 3.0
*/ */
public static final int MLSD = 38; public static final int MLSD = 38;
/** /**
* Machine parseable list for a single file * Machine parseable list for a single file
*
* @since 3.0 * @since 3.0
*/ */
public static final int MLST = 39; public static final int MLST = 39;
@ -135,24 +135,24 @@ public final class FTPCommand
public static final int SET_MOD_TIME = MFMT; public static final int SET_MOD_TIME = MFMT;
// Cannot be instantiated // Cannot be instantiated
private FTPCommand() private FTPCommand() {
{} }
private static final String[] _commands = { private static final String[] _commands = {
"USER", "PASS", "ACCT", "CWD", "CDUP", "SMNT", "REIN", "QUIT", "PORT", "USER", "PASS", "ACCT", "CWD", "CDUP", "SMNT", "REIN", "QUIT", "PORT", "PASV", "TYPE", "STRU",
"PASV", "TYPE", "STRU", "MODE", "RETR", "STOR", "STOU", "APPE", "ALLO", "MODE", "RETR", "STOR", "STOU", "APPE", "ALLO", "REST", "RNFR", "RNTO", "ABOR", "DELE", "RMD",
"REST", "RNFR", "RNTO", "ABOR", "DELE", "RMD", "MKD", "PWD", "LIST", "MKD", "PWD", "LIST", "NLST", "SITE", "SYST", "STAT", "HELP", "NOOP", "MDTM", "FEAT", "MFMT",
"NLST", "SITE", "SYST", "STAT", "HELP", "NOOP", "MDTM", "FEAT", "MFMT", "EPSV", "EPRT", "MLSD", "MLST"
"EPSV", "EPRT", "MLSD", "MLST" }; };
// default access needed for Unit test // default access needed for Unit test
static void checkArray(){ static void checkArray() {
int expectedLength = LAST+1; int expectedLength = LAST + 1;
if (_commands.length != expectedLength) { if (_commands.length != expectedLength) {
throw new RuntimeException("Incorrect _commands array. Should have length " throw new RuntimeException("Incorrect _commands array. Should have length "
+expectedLength+" found "+_commands.length); + expectedLength
+ " found "
+ _commands.length);
} }
} }
@ -164,8 +164,7 @@ public final class FTPCommand
* @return The FTP protcol command string corresponding to a specified * @return The FTP protcol command string corresponding to a specified
* command code. * command code.
*/ */
public static final String getCommand(int command) public static final String getCommand(int command) {
{
return _commands[command]; return _commands[command];
} }
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp; package org.apache.commons.net.ftp;
import java.io.IOException; import java.io.IOException;
/*** /***
@ -31,14 +32,12 @@ import java.io.IOException;
* @see FTPClient * @see FTPClient
***/ ***/
public class FTPConnectionClosedException extends IOException public class FTPConnectionClosedException extends IOException {
{
private static final long serialVersionUID = 3500547241659379952L; private static final long serialVersionUID = 3500547241659379952L;
/*** Constructs a FTPConnectionClosedException with no message ***/ /*** Constructs a FTPConnectionClosedException with no message ***/
public FTPConnectionClosedException() public FTPConnectionClosedException() {
{
super(); super();
} }
@ -47,9 +46,7 @@ public class FTPConnectionClosedException extends IOException
* *
* @param message The message explaining the reason for the exception. * @param message The message explaining the reason for the exception.
***/ ***/
public FTPConnectionClosedException(String message) public FTPConnectionClosedException(String message) {
{
super(message); super(message);
} }
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp; package org.apache.commons.net.ftp;
import java.io.Serializable; import java.io.Serializable;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
@ -30,8 +31,7 @@ import java.util.TimeZone;
* @see FTPClient#listFiles * @see FTPClient#listFiles
***/ ***/
public class FTPFile implements Serializable public class FTPFile implements Serializable {
{
private static final long serialVersionUID = 9010790363003271996L; private static final long serialVersionUID = 9010790363003271996L;
/** A constant indicating an FTPFile is a file. ***/ /** A constant indicating an FTPFile is a file. ***/
@ -68,8 +68,7 @@ public class FTPFile implements Serializable
private final boolean[] _permissions[]; // e.g. _permissions[USER_ACCESS][READ_PERMISSION] private final boolean[] _permissions[]; // e.g. _permissions[USER_ACCESS][READ_PERMISSION]
/*** Creates an empty FTPFile. ***/ /*** Creates an empty FTPFile. ***/
public FTPFile() public FTPFile() {
{
_permissions = new boolean[3][3]; _permissions = new boolean[3][3];
_type = UNKNOWN_TYPE; _type = UNKNOWN_TYPE;
// init these to values that do not occur in listings // init these to values that do not occur in listings
@ -85,11 +84,11 @@ public class FTPFile implements Serializable
/** /**
* Constructor for use by {@link FTPListParseEngine} only. * Constructor for use by {@link FTPListParseEngine} only.
* Used to create FTPFile entries for failed parses * Used to create FTPFile entries for failed parses
*
* @param rawListing line that could not be parsed. * @param rawListing line that could not be parsed.
* @since 3.4 * @since 3.4
*/ */
FTPFile(String rawListing) FTPFile(String rawListing) {
{
_permissions = null; // flag that entry is invalid _permissions = null; // flag that entry is invalid
_rawListing = rawListing; _rawListing = rawListing;
_type = UNKNOWN_TYPE; _type = UNKNOWN_TYPE;
@ -103,15 +102,13 @@ public class FTPFile implements Serializable
_name = null; _name = null;
} }
/*** /***
* Set the original FTP server raw listing from which the FTPFile was * Set the original FTP server raw listing from which the FTPFile was
* created. * created.
* *
* @param rawListing The raw FTP server listing. * @param rawListing The raw FTP server listing.
***/ ***/
public void setRawListing(String rawListing) public void setRawListing(String rawListing) {
{
_rawListing = rawListing; _rawListing = rawListing;
} }
@ -121,20 +118,17 @@ public class FTPFile implements Serializable
* @return The original FTP server raw listing used to initialize the * @return The original FTP server raw listing used to initialize the
* FTPFile. * FTPFile.
***/ ***/
public String getRawListing() public String getRawListing() {
{
return _rawListing; return _rawListing;
} }
/*** /***
* Determine if the file is a directory. * Determine if the file is a directory.
* *
* @return True if the file is of type <code>DIRECTORY_TYPE</code>, false if * @return True if the file is of type <code>DIRECTORY_TYPE</code>, false if
* not. * not.
***/ ***/
public boolean isDirectory() public boolean isDirectory() {
{
return (_type == DIRECTORY_TYPE); return (_type == DIRECTORY_TYPE);
} }
@ -144,8 +138,7 @@ public class FTPFile implements Serializable
* @return True if the file is of type <code>FILE_TYPE</code>, false if * @return True if the file is of type <code>FILE_TYPE</code>, false if
* not. * not.
***/ ***/
public boolean isFile() public boolean isFile() {
{
return (_type == FILE_TYPE); return (_type == FILE_TYPE);
} }
@ -155,8 +148,7 @@ public class FTPFile implements Serializable
* @return True if the file is of type <code>UNKNOWN_TYPE</code>, false if * @return True if the file is of type <code>UNKNOWN_TYPE</code>, false if
* not. * not.
***/ ***/
public boolean isSymbolicLink() public boolean isSymbolicLink() {
{
return (_type == SYMBOLIC_LINK_TYPE); return (_type == SYMBOLIC_LINK_TYPE);
} }
@ -166,8 +158,7 @@ public class FTPFile implements Serializable
* @return True if the file is of type <code>UNKNOWN_TYPE</code>, false if * @return True if the file is of type <code>UNKNOWN_TYPE</code>, false if
* not. * not.
***/ ***/
public boolean isUnknown() public boolean isUnknown() {
{
return (_type == UNKNOWN_TYPE); return (_type == UNKNOWN_TYPE);
} }
@ -177,8 +168,9 @@ public class FTPFile implements Serializable
* Other methods may fail. * Other methods may fail.
* *
* Used in conjunction with list parsing that preseverves entries that failed to parse. * Used in conjunction with list parsing that preseverves entries that failed to parse.
* @see FTPClientConfig#setUnparseableEntries(boolean) *
* @return true if the entry is valid * @return true if the entry is valid
* @see FTPClientConfig#setUnparseableEntries(boolean)
* @since 3.4 * @since 3.4
*/ */
public boolean isValid() { public boolean isValid() {
@ -191,31 +183,26 @@ public class FTPFile implements Serializable
* *
* @param type The integer code representing the type of the file. * @param type The integer code representing the type of the file.
***/ ***/
public void setType(int type) public void setType(int type) {
{
_type = type; _type = type;
} }
/*** /***
* Return the type of the file (one of the <code>_TYPE</code> constants), * Return the type of the file (one of the <code>_TYPE</code> constants),
* e.g., if it is a directory, a regular file, or a symbolic link. * e.g., if it is a directory, a regular file, or a symbolic link.
* *
* @return The type of the file. * @return The type of the file.
***/ ***/
public int getType() public int getType() {
{
return _type; return _type;
} }
/*** /***
* Set the name of the file. * Set the name of the file.
* *
* @param name The name of the file. * @param name The name of the file.
***/ ***/
public void setName(String name) public void setName(String name) {
{
_name = name; _name = name;
} }
@ -224,89 +211,75 @@ public class FTPFile implements Serializable
* *
* @return The name of the file. * @return The name of the file.
***/ ***/
public String getName() public String getName() {
{
return _name; return _name;
} }
/** /**
* Set the file size in bytes. * Set the file size in bytes.
*
* @param size The file size in bytes. * @param size The file size in bytes.
*/ */
public void setSize(long size) public void setSize(long size) {
{
_size = size; _size = size;
} }
/*** /***
* Return the file size in bytes. * Return the file size in bytes.
* *
* @return The file size in bytes. * @return The file size in bytes.
***/ ***/
public long getSize() public long getSize() {
{
return _size; return _size;
} }
/*** /***
* Set the number of hard links to this file. This is not to be * Set the number of hard links to this file. This is not to be
* confused with symbolic links. * confused with symbolic links.
* *
* @param links The number of hard links to this file. * @param links The number of hard links to this file.
***/ ***/
public void setHardLinkCount(int links) public void setHardLinkCount(int links) {
{
_hardLinkCount = links; _hardLinkCount = links;
} }
/*** /***
* Return the number of hard links to this file. This is not to be * Return the number of hard links to this file. This is not to be
* confused with symbolic links. * confused with symbolic links.
* *
* @return The number of hard links to this file. * @return The number of hard links to this file.
***/ ***/
public int getHardLinkCount() public int getHardLinkCount() {
{
return _hardLinkCount; return _hardLinkCount;
} }
/*** /***
* Set the name of the group owning the file. This may be * Set the name of the group owning the file. This may be
* a string representation of the group number. * a string representation of the group number.
* *
* @param group The name of the group owning the file. * @param group The name of the group owning the file.
***/ ***/
public void setGroup(String group) public void setGroup(String group) {
{
_group = group; _group = group;
} }
/*** /***
* Returns the name of the group owning the file. Sometimes this will be * Returns the name of the group owning the file. Sometimes this will be
* a string representation of the group number. * a string representation of the group number.
* *
* @return The name of the group owning the file. * @return The name of the group owning the file.
***/ ***/
public String getGroup() public String getGroup() {
{
return _group; return _group;
} }
/*** /***
* Set the name of the user owning the file. This may be * Set the name of the user owning the file. This may be
* a string representation of the user number; * a string representation of the user number;
* *
* @param user The name of the user owning the file. * @param user The name of the user owning the file.
***/ ***/
public void setUser(String user) public void setUser(String user) {
{
_user = user; _user = user;
} }
@ -316,24 +289,20 @@ public class FTPFile implements Serializable
* *
* @return The name of the user owning the file. * @return The name of the user owning the file.
***/ ***/
public String getUser() public String getUser() {
{
return _user; return _user;
} }
/*** /***
* If the FTPFile is a symbolic link, use this method to set the name of the * If the FTPFile is a symbolic link, use this method to set the name of the
* file being pointed to by the symbolic link. * file being pointed to by the symbolic link.
* *
* @param link The file pointed to by the symbolic link. * @param link The file pointed to by the symbolic link.
***/ ***/
public void setLink(String link) public void setLink(String link) {
{
_link = link; _link = link;
} }
/*** /***
* If the FTPFile is a symbolic link, this method returns the name of the * 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. * file being pointed to by the symbolic link. Otherwise it returns null.
@ -341,12 +310,10 @@ public class FTPFile implements Serializable
* @return The file pointed to by the symbolic link (null if the FTPFile * @return The file pointed to by the symbolic link (null if the FTPFile
* is not a symbolic link). * is not a symbolic link).
***/ ***/
public String getLink() public String getLink() {
{
return _link; return _link;
} }
/*** /***
* Set the file timestamp. This usually the last modification time. * Set the file timestamp. This usually the last modification time.
* The parameter is not cloned, so do not alter its value after calling * The parameter is not cloned, so do not alter its value after calling
@ -354,23 +321,19 @@ public class FTPFile implements Serializable
* *
* @param date A Calendar instance representing the file timestamp. * @param date A Calendar instance representing the file timestamp.
***/ ***/
public void setTimestamp(Calendar date) public void setTimestamp(Calendar date) {
{
_date = date; _date = date;
} }
/*** /***
* Returns the file timestamp. This usually the last modification time. * Returns the file timestamp. This usually the last modification time.
* *
* @return A Calendar instance representing the file timestamp. * @return A Calendar instance representing the file timestamp.
***/ ***/
public Calendar getTimestamp() public Calendar getTimestamp() {
{
return _date; return _date;
} }
/*** /***
* Set if the given access group (one of the <code> _ACCESS </code> * Set if the given access group (one of the <code> _ACCESS </code>
* constants) has the given access permission (one of the * constants) has the given access permission (one of the
@ -383,12 +346,10 @@ public class FTPFile implements Serializable
* @param value True if permission is allowed, false if not. * @param value True if permission is allowed, false if not.
* @throws ArrayIndexOutOfBoundsException if either of the parameters is out of range * @throws ArrayIndexOutOfBoundsException if either of the parameters is out of range
***/ ***/
public void setPermission(int access, int permission, boolean value) public void setPermission(int access, int permission, boolean value) {
{
_permissions[access][permission] = value; _permissions[access][permission] = value;
} }
/*** /***
* Determines if the given access group (one of the <code> _ACCESS </code> * Determines if the given access group (one of the <code> _ACCESS </code>
* constants) has the given access permission (one of the * constants) has the given access permission (one of the
@ -402,8 +363,7 @@ public class FTPFile implements Serializable
* @return true if {@link #isValid()} is {@code true &&} the associated permission is set; * @return true if {@link #isValid()} is {@code true &&} the associated permission is set;
* {@code false} otherwise. * {@code false} otherwise.
***/ ***/
public boolean hasPermission(int access, int permission) public boolean hasPermission(int access, int permission) {
{
if (_permissions == null) { if (_permissions == null) {
return false; return false;
} }
@ -415,9 +375,7 @@ public class FTPFile implements Serializable
* *
* @return A string representation of the FTPFile information. * @return A string representation of the FTPFile information.
*/ */
@Override @Override public String toString() {
public String toString()
{
return getRawListing(); return getRawListing();
} }
@ -435,8 +393,7 @@ public class FTPFile implements Serializable
* @return A string representation of the FTPFile information. * @return A string representation of the FTPFile information.
* @since 3.0 * @since 3.0
*/ */
public String toFormattedString() public String toFormattedString() {
{
return toFormattedString(null); return toFormattedString(null);
} }
@ -448,13 +405,13 @@ public class FTPFile implements Serializable
* Note: if the instance is not valid {@link #isValid()}, no useful * Note: if the instance is not valid {@link #isValid()}, no useful
* information can be returned. In this case, use {@link #getRawListing()} * information can be returned. In this case, use {@link #getRawListing()}
* instead. * instead.
*
* @param timezone the timezone to use for displaying the time stamp * @param timezone the timezone to use for displaying the time stamp
* If {@code null}, then use the Calendar entry timezone * If {@code null}, then use the Calendar entry timezone
* @return A string representation of the FTPFile information. * @return A string representation of the FTPFile information.
* @since 3.4 * @since 3.4
*/ */
public String toFormattedString(final String timezone) public String toFormattedString(final String timezone) {
{
if (!isValid()) { if (!isValid()) {
return "[Invalid: could not parse file entry]"; return "[Invalid: could not parse file entry]";
@ -472,7 +429,7 @@ public class FTPFile implements Serializable
if (timestamp != null) { if (timestamp != null) {
if (timezone != null) { if (timezone != null) {
TimeZone newZone = TimeZone.getTimeZone(timezone); TimeZone newZone = TimeZone.getTimeZone(timezone);
if (!newZone.equals(timestamp.getTimeZone())){ if (!newZone.equals(timestamp.getTimeZone())) {
Date original = timestamp.getTime(); Date original = timestamp.getTime();
Calendar newStamp = Calendar.getInstance(newZone); Calendar newStamp = Calendar.getInstance(newZone);
newStamp.setTime(original); newStamp.setTime(original);
@ -501,8 +458,8 @@ public class FTPFile implements Serializable
return sb.toString(); return sb.toString();
} }
private char formatType(){ private char formatType() {
switch(_type) { switch (_type) {
case FILE_TYPE: case FILE_TYPE:
return '-'; return '-';
case DIRECTORY_TYPE: case DIRECTORY_TYPE:
@ -514,7 +471,7 @@ public class FTPFile implements Serializable
} }
} }
private String permissionToString(int access ){ private String permissionToString(int access) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if (hasPermission(access, READ_PERMISSION)) { if (hasPermission(access, READ_PERMISSION)) {
sb.append('r'); sb.append('r');

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp; package org.apache.commons.net.ftp;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -78,8 +79,7 @@ import java.util.List;
* @see FTPFile * @see FTPFile
* @see FTPClient#listFiles() * @see FTPClient#listFiles()
*/ */
public interface FTPFileEntryParser public interface FTPFileEntryParser {
{
/** /**
* Parses a line of an FTP server file listing and converts it into a usable * Parses a line of an FTP server file listing and converts it into a usable
* format in the form of an <code> FTPFile </code> instance. If the * format in the form of an <code> FTPFile </code> instance. If the
@ -100,13 +100,11 @@ public interface FTPFileEntryParser
* *
* @param reader The BufferedReader object from which entries are to be * @param reader The BufferedReader object from which entries are to be
* read. * read.
*
* @return A string representing the next ftp entry or null if none found. * @return A string representing the next ftp entry or null if none found.
* @throws IOException thrown on any IO Error reading from the reader. * @throws IOException thrown on any IO Error reading from the reader.
*/ */
String readNextEntry(BufferedReader reader) throws IOException; String readNextEntry(BufferedReader reader) throws IOException;
/** /**
* This method is a hook for those implementors (such as * This method is a hook for those implementors (such as
* VMSVersioningFTPEntryParser, and possibly others) which need to * VMSVersioningFTPEntryParser, and possibly others) which need to
@ -116,12 +114,9 @@ public interface FTPFileEntryParser
* The default implementation can be a no-op. * The default implementation can be a no-op.
* *
* @param original Original list after it has been created from the server stream * @param original Original list after it has been created from the server stream
*
* @return Original list as processed by this method. * @return Original list as processed by this method.
*/ */
List<String> preParse(List<String> original); List<String> preParse(List<String> original);
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp; package org.apache.commons.net.ftp;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -24,16 +25,12 @@ import java.util.List;
* This abstract class implements both the older FTPFileListParser and * This abstract class implements both the older FTPFileListParser and
* newer FTPFileEntryParser interfaces with default functionality. * newer FTPFileEntryParser interfaces with default functionality.
* All the classes in the parser subpackage inherit from this. * All the classes in the parser subpackage inherit from this.
*
*/ */
public abstract class FTPFileEntryParserImpl public abstract class FTPFileEntryParserImpl implements FTPFileEntryParser {
implements FTPFileEntryParser
{
/** /**
* The constructor for a FTPFileEntryParserImpl object. * The constructor for a FTPFileEntryParserImpl object.
*/ */
public FTPFileEntryParserImpl() public FTPFileEntryParserImpl() {
{
} }
/** /**
@ -43,15 +40,13 @@ public abstract class FTPFileEntryParserImpl
* *
* @param reader The BufferedReader object from which entries are to be * @param reader The BufferedReader object from which entries are to be
* read. * read.
*
* @return A string representing the next ftp entry or null if none found. * @return A string representing the next ftp entry or null if none found.
* @throws IOException thrown on any IO Error reading from the reader. * @throws IOException thrown on any IO Error reading from the reader.
*/ */
@Override @Override public String readNextEntry(BufferedReader reader) throws IOException {
public String readNextEntry(BufferedReader reader) throws IOException
{
return reader.readLine(); return reader.readLine();
} }
/** /**
* This method is a hook for those implementors (such as * This method is a hook for those implementors (such as
* VMSVersioningFTPEntryParser, and possibly others) which need to * VMSVersioningFTPEntryParser, and possibly others) which need to
@ -61,11 +56,9 @@ public abstract class FTPFileEntryParserImpl
* This default implementation does nothing. * This default implementation does nothing.
* *
* @param original Original list after it has been created from the server stream * @param original Original list after it has been created from the server stream
*
* @return <code>original</code> unmodified. * @return <code>original</code> unmodified.
*/ */
@Override @Override public List<String> preParse(List<String> original) {
public List<String> preParse(List<String> original) {
return original; return original;
} }
} }

@ -20,6 +20,7 @@ package org.apache.commons.net.ftp;
/** /**
* Perform filtering on FTPFile entries. * Perform filtering on FTPFile entries.
*
* @since 2.2 * @since 2.2
*/ */
public interface FTPFileFilter { public interface FTPFileFilter {

@ -20,6 +20,7 @@ package org.apache.commons.net.ftp;
/** /**
* Implements some simple FTPFileFilter classes. * Implements some simple FTPFileFilter classes.
*
* @since 2.2 * @since 2.2
*/ */
public class FTPFileFilters { public class FTPFileFilters {
@ -28,8 +29,7 @@ public class FTPFileFilters {
* Accepts all FTPFile entries, including null. * Accepts all FTPFile entries, including null.
*/ */
public static final FTPFileFilter ALL = new FTPFileFilter() { public static final FTPFileFilter ALL = new FTPFileFilter() {
@Override @Override public boolean accept(FTPFile file) {
public boolean accept(FTPFile file) {
return true; return true;
} }
}; };
@ -38,8 +38,7 @@ public class FTPFileFilters {
* Accepts all non-null FTPFile entries. * Accepts all non-null FTPFile entries.
*/ */
public static final FTPFileFilter NON_NULL = new FTPFileFilter() { public static final FTPFileFilter NON_NULL = new FTPFileFilter() {
@Override @Override public boolean accept(FTPFile file) {
public boolean accept(FTPFile file) {
return file != null; return file != null;
} }
}; };
@ -48,10 +47,8 @@ public class FTPFileFilters {
* Accepts all (non-null) FTPFile directory entries. * Accepts all (non-null) FTPFile directory entries.
*/ */
public static final FTPFileFilter DIRECTORIES = new FTPFileFilter() { public static final FTPFileFilter DIRECTORIES = new FTPFileFilter() {
@Override @Override public boolean accept(FTPFile file) {
public boolean accept(FTPFile file) {
return file != null && file.isDirectory(); return file != null && file.isDirectory();
} }
}; };
} }

@ -43,7 +43,7 @@ public class FTPHTTPClient extends FTPClient {
private final String proxyUsername; private final String proxyUsername;
private final String proxyPassword; private final String proxyPassword;
private static final byte[] CRLF={'\r', '\n'}; private static final byte[] CRLF = { '\r', '\n' };
private final Base64 base64 = new Base64(); private final Base64 base64 = new Base64();
private String tunnelHost; // Save the host when setting up a tunnel (needed for EPSV) private String tunnelHost; // Save the host when setting up a tunnel (needed for EPSV)
@ -60,7 +60,6 @@ public class FTPHTTPClient extends FTPClient {
this(proxyHost, proxyPort, null, null); this(proxyHost, proxyPort, null, null);
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
* *
@ -69,9 +68,7 @@ public class FTPHTTPClient extends FTPClient {
*/ */
// Kept to maintain binary compatibility // Kept to maintain binary compatibility
// Not strictly necessary, but Clirr complains even though there is a super-impl // Not strictly necessary, but Clirr complains even though there is a super-impl
@Override @Override @Deprecated protected Socket _openDataConnection_(int command, String arg)
@Deprecated
protected Socket _openDataConnection_(int command, String arg)
throws IOException { throws IOException {
return super._openDataConnection_(command, arg); return super._openDataConnection_(command, arg);
} }
@ -82,9 +79,7 @@ public class FTPHTTPClient extends FTPClient {
* @throws IllegalStateException if connection mode is not passive * @throws IllegalStateException if connection mode is not passive
* @since 3.1 * @since 3.1
*/ */
@Override @Override protected Socket _openDataConnection_(String command, String arg) throws IOException {
protected Socket _openDataConnection_(String command, String arg)
throws IOException {
//Force local passive mode, active mode not supported by through proxy //Force local passive mode, active mode not supported by through proxy
if (getDataConnectionMode() != PASSIVE_LOCAL_DATA_CONNECTION_MODE) { if (getDataConnectionMode() != PASSIVE_LOCAL_DATA_CONNECTION_MODE) {
throw new IllegalStateException("Only passive connection mode supported"); throw new IllegalStateException("Only passive connection mode supported");
@ -126,8 +121,7 @@ public class FTPHTTPClient extends FTPClient {
return socket; return socket;
} }
@Override @Override public void connect(String host, int port) throws SocketException, IOException {
public void connect(String host, int port) throws SocketException, IOException {
_socket_ = _socketFactory_.createSocket(proxyHost, proxyPort); _socket_ = _socketFactory_.createSocket(proxyHost, proxyPort);
_input_ = _socket_.getInputStream(); _input_ = _socket_.getInputStream();
@ -135,17 +129,16 @@ public class FTPHTTPClient extends FTPClient {
Reader socketIsReader; Reader socketIsReader;
try { try {
socketIsReader = tunnelHandshake(host, port, _input_, _output_); socketIsReader = tunnelHandshake(host, port, _input_, _output_);
} } catch (Exception e) {
catch (Exception e) { IOException ioe = new IOException("Could not connect to " + host + " using port " + port);
IOException ioe = new IOException("Could not connect to " + host+ " using port " + port);
ioe.initCause(e); ioe.initCause(e);
throw ioe; throw ioe;
} }
super._connectAction_(socketIsReader); super._connectAction_(socketIsReader);
} }
private BufferedReader tunnelHandshake(String host, int port, InputStream input, OutputStream output) throws IOException, private BufferedReader tunnelHandshake(String host, int port, InputStream input,
UnsupportedEncodingException { OutputStream output) throws IOException, UnsupportedEncodingException {
final String connectString = "CONNECT " + host + ":" + port + " HTTP/1.1"; final String connectString = "CONNECT " + host + ":" + port + " HTTP/1.1";
final String hostString = "Host: " + host + ":" + port; final String hostString = "Host: " + host + ":" + port;
@ -157,18 +150,17 @@ public class FTPHTTPClient extends FTPClient {
if (proxyUsername != null && proxyPassword != null) { if (proxyUsername != null && proxyPassword != null) {
final String auth = proxyUsername + ":" + proxyPassword; final String auth = proxyUsername + ":" + proxyPassword;
final String header = "Proxy-Authorization: Basic " final String header =
+ base64.encodeToString(auth.getBytes("UTF-8")); "Proxy-Authorization: Basic " + base64.encodeToString(auth.getBytes("UTF-8"));
output.write(header.getBytes("UTF-8")); output.write(header.getBytes("UTF-8"));
} }
output.write(CRLF); output.write(CRLF);
List<String> response = new ArrayList<String>(); List<String> response = new ArrayList<String>();
BufferedReader reader = new BufferedReader( BufferedReader reader = new BufferedReader(new InputStreamReader(input, getCharset()));
new InputStreamReader(input, getCharset()));
for (String line = reader.readLine(); line != null for (String line = reader.readLine(); line != null && line.length() > 0;
&& line.length() > 0; line = reader.readLine()) { line = reader.readLine()) {
response.add(line); response.add(line);
} }

@ -29,7 +29,6 @@ import java.util.ListIterator;
import org.apache.commons.net.util.Charsets; import org.apache.commons.net.util.Charsets;
/** /**
* This class handles the entire process of parsing a listing of * This class handles the entire process of parsing a listing of
* file entries from the server. * file entries from the server.
@ -73,6 +72,7 @@ import org.apache.commons.net.util.Charsets;
* <p> * <p>
* For unpaged access, simply use FTPClient.listFiles(). That method * For unpaged access, simply use FTPClient.listFiles(). That method
* uses this class transparently. * uses this class transparently.
*
* @version $Id: FTPListParseEngine.java 1747119 2016-06-07 02:22:24Z ggregory $ * @version $Id: FTPListParseEngine.java 1747119 2016-06-07 02:22:24Z ggregory $
*/ */
public class FTPListParseEngine { public class FTPListParseEngine {
@ -89,6 +89,7 @@ public class FTPListParseEngine {
/** /**
* Intended for use by FTPClient only * Intended for use by FTPClient only
*
* @since 3.4 * @since 3.4
*/ */
FTPListParseEngine(FTPFileEntryParser parser, FTPClientConfig configuration) { FTPListParseEngine(FTPFileEntryParser parser, FTPClientConfig configuration) {
@ -108,13 +109,9 @@ public class FTPListParseEngine {
* *
* @param stream input stream provided by the server socket. * @param stream input stream provided by the server socket.
* @param encoding the encoding to be used for reading the stream * @param encoding the encoding to be used for reading the stream
* * @throws IOException thrown on any failure to read from the sever.
* @throws IOException
* thrown on any failure to read from the sever.
*/ */
public void readServerList(InputStream stream, String encoding) public void readServerList(InputStream stream, String encoding) throws IOException {
throws IOException
{
this.entries = new LinkedList<String>(); this.entries = new LinkedList<String>();
readStream(stream, encoding); readStream(stream, encoding);
this.parser.preParse(this.entries); this.parser.preParse(this.entries);
@ -131,19 +128,15 @@ public class FTPListParseEngine {
* *
* @param stream The socket stream on which the input will be read. * @param stream The socket stream on which the input will be read.
* @param encoding The encoding to use. * @param encoding The encoding to use.
* * @throws IOException thrown on any failure to read the stream
* @throws IOException
* thrown on any failure to read the stream
*/ */
private void readStream(InputStream stream, String encoding) throws IOException private void readStream(InputStream stream, String encoding) throws IOException {
{ BufferedReader reader =
BufferedReader reader = new BufferedReader( new BufferedReader(new InputStreamReader(stream, Charsets.toCharset(encoding)));
new InputStreamReader(stream, Charsets.toCharset(encoding)));
String line = this.parser.readNextEntry(reader); String line = this.parser.readNextEntry(reader);
while (line != null) while (line != null) {
{
this.entries.add(line); this.entries.add(line);
line = this.parser.readNextEntry(reader); line = this.parser.readNextEntry(reader);
} }
@ -161,9 +154,7 @@ public class FTPListParseEngine {
* After this method is called this object's internal iterator is advanced * 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. * by a number of positions equal to the size of the array returned.
* *
* @param quantityRequested * @param quantityRequested the maximum number of entries we want to get.
* the maximum number of entries we want to get.
*
* @return an array of at most <code>quantityRequested</code> FTPFile * @return an array of at most <code>quantityRequested</code> FTPFile
* objects starting at the current position of this iterator within its * 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 * list and at least the number of elements which exist in the list at
@ -186,7 +177,6 @@ public class FTPListParseEngine {
count--; count--;
} }
return tmpResults.toArray(new FTPFile[tmpResults.size()]); return tmpResults.toArray(new FTPFile[tmpResults.size()]);
} }
/** /**
@ -202,9 +192,7 @@ public class FTPListParseEngine {
* After this method is called this object's internal iterator is moved * 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. * back by a number of positions equal to the size of the array returned.
* *
* @param quantityRequested * @param quantityRequested the maximum number of entries we want to get.
* the maximum number of entries we want to get.
*
* @return an array of at most <code>quantityRequested</code> FTPFile * @return an array of at most <code>quantityRequested</code> FTPFile
* objects starting at the current position of this iterator within its * 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 * list and at least the number of elements which exist in the list at
@ -224,7 +212,7 @@ public class FTPListParseEngine {
if (temp == null && saveUnparseableEntries) { if (temp == null && saveUnparseableEntries) {
temp = new FTPFile(entry); temp = new FTPFile(entry);
} }
tmpResults.add(0,temp); tmpResults.add(0, temp);
count--; count--;
} }
return tmpResults.toArray(new FTPFile[tmpResults.size()]); return tmpResults.toArray(new FTPFile[tmpResults.size()]);
@ -239,8 +227,7 @@ public class FTPListParseEngine {
* None of the entries will be null * None of the entries will be null
* @throws IOException - not ever thrown, may be removed in a later release * @throws IOException - not ever thrown, may be removed in a later release
*/ */
public FTPFile[] getFiles() public FTPFile[] getFiles() throws IOException // TODO remove; not actually thrown
throws IOException // TODO remove; not actually thrown
{ {
return getFiles(FTPFileFilters.NON_NULL); return getFiles(FTPFileFilters.NON_NULL);
} }
@ -251,7 +238,6 @@ public class FTPListParseEngine {
* The files are filtered before being added to the array. * The files are filtered before being added to the array.
* *
* @param filter FTPFileFilter, must not be <code>null</code>. * @param filter FTPFileFilter, must not be <code>null</code>.
*
* @return an array of FTPFile objects containing the whole list of * @return an array of FTPFile objects containing the whole list of
* files returned by the server as read by this object's parser. * files returned by the server as read by this object's parser.
* <p><b> * <p><b>
@ -260,8 +246,8 @@ public class FTPListParseEngine {
* check each entry for null before referencing it, or use the * check each entry for null before referencing it, or use the
* a filter such as {@link FTPFileFilters#NON_NULL} which does not * a filter such as {@link FTPFileFilters#NON_NULL} which does not
* allow null entries. * allow null entries.
* @since 2.2
* @throws IOException - not ever thrown, may be removed in a later release * @throws IOException - not ever thrown, may be removed in a later release
* @since 2.2
*/ */
public FTPFile[] getFiles(FTPFileFilter filter) public FTPFile[] getFiles(FTPFileFilter filter)
throws IOException // TODO remove; not actually thrown throws IOException // TODO remove; not actually thrown
@ -274,12 +260,11 @@ public class FTPListParseEngine {
if (temp == null && saveUnparseableEntries) { if (temp == null && saveUnparseableEntries) {
temp = new FTPFile(entry); temp = new FTPFile(entry);
} }
if (filter.accept(temp)){ if (filter.accept(temp)) {
tmpResults.add(temp); tmpResults.add(temp);
} }
} }
return tmpResults.toArray(new FTPFile[tmpResults.size()]); return tmpResults.toArray(new FTPFile[tmpResults.size()]);
} }
/** /**
@ -315,15 +300,12 @@ public class FTPListParseEngine {
/** /**
* Do not use. * Do not use.
*
* @param stream the stream from which to read * @param stream the stream from which to read
* @throws IOException on error * @throws IOException on error
* @deprecated use {@link #readServerList(InputStream, String)} instead * @deprecated use {@link #readServerList(InputStream, String)} instead
*/ */
@Deprecated @Deprecated public void readServerList(InputStream stream) throws IOException {
public void readServerList(InputStream stream)
throws IOException
{
readServerList(stream, null); readServerList(stream, null);
} }
} }

@ -26,8 +26,7 @@ package org.apache.commons.net.ftp;
* TODO replace with an enum * TODO replace with an enum
***/ ***/
public final class FTPReply public final class FTPReply {
{
public static final int RESTART_MARKER = 110; public static final int RESTART_MARKER = 110;
public static final int SERVICE_NOT_READY = 120; public static final int SERVICE_NOT_READY = 120;
@ -100,8 +99,8 @@ public final class FTPReply
public static final int EXTENDED_PORT_FAILURE = 522; public static final int EXTENDED_PORT_FAILURE = 522;
// Cannot be instantiated // Cannot be instantiated
private FTPReply() private FTPReply() {
{} }
/*** /***
* Determine if a reply code is a positive preliminary response. All * Determine if a reply code is a positive preliminary response. All
@ -115,8 +114,7 @@ public final class FTPReply
* @return True if a reply code is a postive preliminary response, false * @return True if a reply code is a postive preliminary response, false
* if not. * if not.
***/ ***/
public static boolean isPositivePreliminary(int reply) public static boolean isPositivePreliminary(int reply) {
{
return (reply >= 100 && reply < 200); return (reply >= 100 && reply < 200);
} }
@ -130,8 +128,7 @@ public final class FTPReply
* @return True if a reply code is a postive completion response, false * @return True if a reply code is a postive completion response, false
* if not. * if not.
***/ ***/
public static boolean isPositiveCompletion(int reply) public static boolean isPositiveCompletion(int reply) {
{
return (reply >= 200 && reply < 300); return (reply >= 200 && reply < 300);
} }
@ -148,8 +145,7 @@ public final class FTPReply
* @return True if a reply code is a postive intermediate response, false * @return True if a reply code is a postive intermediate response, false
* if not. * if not.
***/ ***/
public static boolean isPositiveIntermediate(int reply) public static boolean isPositiveIntermediate(int reply) {
{
return (reply >= 300 && reply < 400); return (reply >= 300 && reply < 400);
} }
@ -163,8 +159,7 @@ public final class FTPReply
* @return True if a reply code is a negative transient response, false * @return True if a reply code is a negative transient response, false
* if not. * if not.
***/ ***/
public static boolean isNegativeTransient(int reply) public static boolean isNegativeTransient(int reply) {
{
return (reply >= 400 && reply < 500); return (reply >= 400 && reply < 500);
} }
@ -178,24 +173,21 @@ public final class FTPReply
* @return True if a reply code is a negative permanent response, false * @return True if a reply code is a negative permanent response, false
* if not. * if not.
***/ ***/
public static boolean isNegativePermanent(int reply) public static boolean isNegativePermanent(int reply) {
{
return (reply >= 500 && reply < 600); return (reply >= 500 && reply < 600);
} }
/** /**
* Determine if a reply code is a protected response. * Determine if a reply code is a protected response.
*
* @param reply The reply code to test. * @param reply The reply code to test.
* @return True if a reply code is a protected response, false * @return True if a reply code is a protected response, false
* if not. * if not.
* @since 3.0 * @since 3.0
*/ */
public static boolean isProtectedReplyCode(int reply) public static boolean isProtectedReplyCode(int reply) {
{
// actually, only 3 protected reply codes are // actually, only 3 protected reply codes are
// defined in RFC 2228: 631, 632 and 633. // defined in RFC 2228: 631, 632 and 633.
return (reply >= 600 && reply < 700); return (reply >= 600 && reply < 700);
} }
} }

@ -45,23 +45,24 @@ import org.apache.commons.net.util.TrustManagerUtils;
* Warning: the hostname is not verified against the certificate by default, use * Warning: the hostname is not verified against the certificate by default, use
* {@link #setHostnameVerifier(HostnameVerifier)} or {@link #setEndpointCheckingEnabled(boolean)} * {@link #setHostnameVerifier(HostnameVerifier)} or {@link #setEndpointCheckingEnabled(boolean)}
* (on Java 1.7+) to enable verification. Verification is only performed on client mode connections. * (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 $ * @version $Id: FTPSClient.java 1747829 2016-06-11 00:57:57Z sebb $
* @since 2.0 * @since 2.0
*/ */
public class FTPSClient extends FTPClient { public class FTPSClient extends FTPClient {
// From http://www.iana.org/assignments/port-numbers // From http://www.iana.org/assignments/port-numbers
// ftps-data 989/tcp ftp protocol, data, over TLS/SSL // ftps-data 989/tcp ftp protocol, data, over TLS/SSL
// ftps-data 989/udp 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/tcp ftp protocol, control, over TLS/SSL
// ftps 990/udp 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_DATA_PORT = 989;
public static final int DEFAULT_FTPS_PORT = 990; public static final int DEFAULT_FTPS_PORT = 990;
/** The value that I can set in PROT command (C = Clear, P = Protected) */ /** The value that I can set in PROT command (C = Clear, P = Protected) */
private static final String[] PROT_COMMAND_VALUE = {"C","E","S","P"}; private static final String[] PROT_COMMAND_VALUE = { "C", "E", "S", "P" };
/** Default PROT Command */ /** Default PROT Command */
private static final String DEFAULT_PROT = "C"; private static final String DEFAULT_PROT = "C";
/** Default secure socket protocol name, i.e. TLS */ /** Default secure socket protocol name, i.e. TLS */
@ -107,7 +108,8 @@ public class FTPSClient extends FTPClient {
/** The protocol versions */ /** The protocol versions */
private String[] protocols = null; private String[] protocols = null;
/** The FTPS {@link TrustManager} implementation, default validate only /**
* The FTPS {@link TrustManager} implementation, default validate only
* {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}. * {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}.
*/ */
private TrustManager trustManager = TrustManagerUtils.getValidateServerCertificateTrustManager(); private TrustManager trustManager = TrustManagerUtils.getValidateServerCertificateTrustManager();
@ -124,7 +126,8 @@ public class FTPSClient extends FTPClient {
/** /**
* Constructor for FTPSClient, calls {@link #FTPSClient(String, boolean)}. * Constructor for FTPSClient, calls {@link #FTPSClient(String, boolean)}.
* *
* Sets protocol to {@link #DEFAULT_PROTOCOL} - i.e. TLS - and security mode to explicit (isImplicit = false) * Sets protocol to {@link #DEFAULT_PROTOCOL} - i.e. TLS - and security mode to explicit
* (isImplicit = false)
*/ */
public FTPSClient() { public FTPSClient() {
this(DEFAULT_PROTOCOL, false); this(DEFAULT_PROTOCOL, false);
@ -133,6 +136,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS
* Calls {@link #FTPSClient(String, boolean)} * Calls {@link #FTPSClient(String, boolean)}
*
* @param isImplicit The security mode (Implicit/Explicit). * @param isImplicit The security mode (Implicit/Explicit).
*/ */
public FTPSClient(boolean isImplicit) { public FTPSClient(boolean isImplicit) {
@ -153,6 +157,7 @@ public class FTPSClient extends FTPClient {
* and security mode. If isImplicit is true, the port is set to * and security mode. If isImplicit is true, the port is set to
* {@link #DEFAULT_FTPS_PORT} i.e. 990. * {@link #DEFAULT_FTPS_PORT} i.e. 990.
* The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()} * The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}
*
* @param protocol the protocol * @param protocol the protocol
* @param isImplicit The security mode(Implicit/Explicit). * @param isImplicit The security mode(Implicit/Explicit).
*/ */
@ -168,6 +173,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS
* The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()} * The default TrustManager is set from {@link TrustManagerUtils#getValidateServerCertificateTrustManager()}
*
* @param isImplicit The security mode(Implicit/Explicit). * @param isImplicit The security mode(Implicit/Explicit).
* @param context A pre-configured SSL Context * @param context A pre-configured SSL Context
*/ */
@ -180,16 +186,17 @@ public class FTPSClient extends FTPClient {
* Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS * Constructor for FTPSClient, using {@link #DEFAULT_PROTOCOL} - i.e. TLS
* and isImplicit {@code false} * and isImplicit {@code false}
* Calls {@link #FTPSClient(boolean, SSLContext)} * Calls {@link #FTPSClient(boolean, SSLContext)}
*
* @param context A pre-configured SSL Context * @param context A pre-configured SSL Context
*/ */
public FTPSClient(SSLContext context) { public FTPSClient(SSLContext context) {
this(false, context); this(false, context);
} }
/** /**
* Set AUTH command use value. * Set AUTH command use value.
* This processing is done before connected processing. * This processing is done before connected processing.
*
* @param auth AUTH command use value. * @param auth AUTH command use value.
*/ */
public void setAuthValue(String auth) { public void setAuthValue(String auth) {
@ -198,23 +205,23 @@ public class FTPSClient extends FTPClient {
/** /**
* Return AUTH command use value. * Return AUTH command use value.
*
* @return AUTH command use value. * @return AUTH command use value.
*/ */
public String getAuthValue() { public String getAuthValue() {
return this.auth; return this.auth;
} }
/** /**
* Because there are so many connect() methods, * Because there are so many connect() methods,
* the _connectAction_() method is provided as a means of performing * the _connectAction_() method is provided as a means of performing
* some action immediately after establishing a connection, * some action immediately after establishing a connection,
* rather than reimplementing all of the connect() methods. * rather than reimplementing all of the connect() methods.
*
* @throws IOException If it throw by _connectAction_. * @throws IOException If it throw by _connectAction_.
* @see org.apache.commons.net.SocketClient#_connectAction_() * @see org.apache.commons.net.SocketClient#_connectAction_()
*/ */
@Override @Override protected void _connectAction_() throws IOException {
protected void _connectAction_() throws IOException {
// Implicit mode. // Implicit mode.
if (isImplicit) { if (isImplicit) {
sslNegotiation(); sslNegotiation();
@ -229,6 +236,7 @@ public class FTPSClient extends FTPClient {
/** /**
* AUTH command. * AUTH command.
*
* @throws SSLException If it server reply code not equal "234" and "334". * @throws SSLException If it server reply code not equal "234" and "334".
* @throws IOException If an I/O error occurs while either sending * @throws IOException If an I/O error occurs while either sending
* the command. * the command.
@ -245,6 +253,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Performs a lazy init of the SSL context * Performs a lazy init of the SSL context
*
* @throws IOException * @throws IOException
*/ */
private void initSslContext() throws IOException { private void initSslContext() throws IOException {
@ -256,6 +265,7 @@ public class FTPSClient extends FTPClient {
/** /**
* SSL/TLS negotiation. Acquires an SSL socket of a control * SSL/TLS negotiation. Acquires an SSL socket of a control
* connection and carries out handshake processing. * connection and carries out handshake processing.
*
* @throws IOException If server negotiation fails * @throws IOException If server negotiation fails
*/ */
protected void sslNegotiation() throws IOException { protected void sslNegotiation() throws IOException {
@ -265,8 +275,7 @@ public class FTPSClient extends FTPClient {
SSLSocketFactory ssf = context.getSocketFactory(); SSLSocketFactory ssf = context.getSocketFactory();
String host = (_hostname_ != null) ? _hostname_ : getRemoteAddress().getHostAddress(); String host = (_hostname_ != null) ? _hostname_ : getRemoteAddress().getHostAddress();
int port = _socket_.getPort(); int port = _socket_.getPort();
SSLSocket socket = SSLSocket socket = (SSLSocket) ssf.createSocket(_socket_, host, port, false);
(SSLSocket) ssf.createSocket(_socket_, host, port, false);
socket.setEnableSessionCreation(isCreation); socket.setEnableSessionCreation(isCreation);
socket.setUseClientMode(isClientMode); socket.setUseClientMode(isClientMode);
@ -290,10 +299,10 @@ public class FTPSClient extends FTPClient {
// TODO the following setup appears to duplicate that in the super class methods // TODO the following setup appears to duplicate that in the super class methods
_socket_ = socket; _socket_ = socket;
_controlInput_ = new BufferedReader(new InputStreamReader( _controlInput_ =
socket .getInputStream(), getControlEncoding())); new BufferedReader(new InputStreamReader(socket.getInputStream(), getControlEncoding()));
_controlOutput_ = new BufferedWriter(new OutputStreamWriter( _controlOutput_ =
socket.getOutputStream(), getControlEncoding())); new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), getControlEncoding()));
if (isClientMode) { if (isClientMode) {
if (hostnameVerifier != null && !hostnameVerifier.verify(host, socket.getSession())) { if (hostnameVerifier != null && !hostnameVerifier.verify(host, socket.getSession())) {
@ -304,6 +313,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Get the {@link KeyManager} instance. * Get the {@link KeyManager} instance.
*
* @return The {@link KeyManager} instance * @return The {@link KeyManager} instance
*/ */
private KeyManager getKeyManager() { private KeyManager getKeyManager() {
@ -322,6 +332,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Controls whether a new SSL session may be established by this socket. * Controls whether a new SSL session may be established by this socket.
*
* @param isCreation The established socket flag. * @param isCreation The established socket flag.
*/ */
public void setEnabledSessionCreation(boolean isCreation) { public void setEnabledSessionCreation(boolean isCreation) {
@ -331,21 +342,24 @@ public class FTPSClient extends FTPClient {
/** /**
* Returns true if new SSL sessions may be established by this socket. * 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 * When the underlying {@link Socket} instance is not SSL-enabled (i.e. an
* instance of {@link SSLSocket} with {@link SSLSocket}{@link #getEnableSessionCreation()}) enabled, * instance of {@link SSLSocket} with {@link SSLSocket}{@link #getEnableSessionCreation()})
* enabled,
* this returns False. * this returns False.
*
* @return true - Indicates that sessions may be created; * @return true - Indicates that sessions may be created;
* this is the default. * this is the default.
* false - indicates that an existing session must be resumed. * false - indicates that an existing session must be resumed.
*/ */
public boolean getEnableSessionCreation() { public boolean getEnableSessionCreation() {
if (_socket_ instanceof SSLSocket) { if (_socket_ instanceof SSLSocket) {
return ((SSLSocket)_socket_).getEnableSessionCreation(); return ((SSLSocket) _socket_).getEnableSessionCreation();
} }
return false; return false;
} }
/** /**
* Configures the socket to require client authentication. * Configures the socket to require client authentication.
*
* @param isNeedClientAuth The need client auth flag. * @param isNeedClientAuth The need client auth flag.
*/ */
public void setNeedClientAuth(boolean isNeedClientAuth) { public void setNeedClientAuth(boolean isNeedClientAuth) {
@ -355,12 +369,13 @@ public class FTPSClient extends FTPClient {
/** /**
* Returns true if the socket will require client authentication. * Returns true if the socket will require client authentication.
* When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false.
*
* @return true - If the server mode socket should request * @return true - If the server mode socket should request
* that the client authenticate itself. * that the client authenticate itself.
*/ */
public boolean getNeedClientAuth() { public boolean getNeedClientAuth() {
if (_socket_ instanceof SSLSocket) { if (_socket_ instanceof SSLSocket) {
return ((SSLSocket)_socket_).getNeedClientAuth(); return ((SSLSocket) _socket_).getNeedClientAuth();
} }
return false; return false;
} }
@ -369,6 +384,7 @@ public class FTPSClient extends FTPClient {
* Configures the socket to request client authentication, * Configures the socket to request client authentication,
* but only if such a request is appropriate to the cipher * but only if such a request is appropriate to the cipher
* suite negotiated. * suite negotiated.
*
* @param isWantClientAuth The want client auth flag. * @param isWantClientAuth The want client auth flag.
*/ */
public void setWantClientAuth(boolean isWantClientAuth) { public void setWantClientAuth(boolean isWantClientAuth) {
@ -378,12 +394,13 @@ public class FTPSClient extends FTPClient {
/** /**
* Returns true if the socket will request client authentication. * Returns true if the socket will request client authentication.
* When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false.
*
* @return true - If the server mode socket should request * @return true - If the server mode socket should request
* that the client authenticate itself. * that the client authenticate itself.
*/ */
public boolean getWantClientAuth() { public boolean getWantClientAuth() {
if (_socket_ instanceof SSLSocket) { if (_socket_ instanceof SSLSocket) {
return ((SSLSocket)_socket_).getWantClientAuth(); return ((SSLSocket) _socket_).getWantClientAuth();
} }
return false; return false;
} }
@ -391,6 +408,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Configures the socket to use client (or server) mode in its first * Configures the socket to use client (or server) mode in its first
* handshake. * handshake.
*
* @param isClientMode The use client mode flag. * @param isClientMode The use client mode flag.
*/ */
public void setUseClientMode(boolean isClientMode) { public void setUseClientMode(boolean isClientMode) {
@ -401,12 +419,13 @@ public class FTPSClient extends FTPClient {
* Returns true if the socket is set to use client mode * Returns true if the socket is set to use client mode
* in its first handshake. * in its first handshake.
* When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false. * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns false.
*
* @return true - If the socket should start its first handshake * @return true - If the socket should start its first handshake
* in "client" mode. * in "client" mode.
*/ */
public boolean getUseClientMode() { public boolean getUseClientMode() {
if (_socket_ instanceof SSLSocket) { if (_socket_ instanceof SSLSocket) {
return ((SSLSocket)_socket_).getUseClientMode(); return ((SSLSocket) _socket_).getUseClientMode();
} }
return false; return false;
} }
@ -414,6 +433,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Controls which particular cipher suites are enabled for use on this * Controls which particular cipher suites are enabled for use on this
* connection. Called before server negotiation. * connection. Called before server negotiation.
*
* @param cipherSuites The cipher suites. * @param cipherSuites The cipher suites.
*/ */
public void setEnabledCipherSuites(String[] cipherSuites) { public void setEnabledCipherSuites(String[] cipherSuites) {
@ -425,11 +445,12 @@ public class FTPSClient extends FTPClient {
* Returns the names of the cipher suites which could be enabled * Returns the names of the cipher suites which could be enabled
* for use on this connection. * for use on this connection.
* When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null. * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null.
*
* @return An array of cipher suite names, or <code>null</code> * @return An array of cipher suite names, or <code>null</code>
*/ */
public String[] getEnabledCipherSuites() { public String[] getEnabledCipherSuites() {
if (_socket_ instanceof SSLSocket) { if (_socket_ instanceof SSLSocket) {
return ((SSLSocket)_socket_).getEnabledCipherSuites(); return ((SSLSocket) _socket_).getEnabledCipherSuites();
} }
return null; return null;
} }
@ -437,6 +458,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Controls which particular protocol versions are enabled for use on this * Controls which particular protocol versions are enabled for use on this
* connection. I perform setting before a server negotiation. * connection. I perform setting before a server negotiation.
*
* @param protocolVersions The protocol versions. * @param protocolVersions The protocol versions.
*/ */
public void setEnabledProtocols(String[] protocolVersions) { public void setEnabledProtocols(String[] protocolVersions) {
@ -448,17 +470,19 @@ public class FTPSClient extends FTPClient {
* Returns the names of the protocol versions which are currently * Returns the names of the protocol versions which are currently
* enabled for use on this connection. * enabled for use on this connection.
* When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null. * When the underlying {@link Socket} is not an {@link SSLSocket} instance, returns null.
*
* @return An array of protocols, or <code>null</code> * @return An array of protocols, or <code>null</code>
*/ */
public String[] getEnabledProtocols() { public String[] getEnabledProtocols() {
if (_socket_ instanceof SSLSocket) { if (_socket_ instanceof SSLSocket) {
return ((SSLSocket)_socket_).getEnabledProtocols(); return ((SSLSocket) _socket_).getEnabledProtocols();
} }
return null; return null;
} }
/** /**
* PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer. * PBSZ command. pbsz value: 0 to (2^32)-1 decimal integer.
*
* @param pbsz Protection Buffer Size. * @param pbsz Protection Buffer Size.
* @throws SSLException If the server reply code does not equal "200". * @throws SSLException If the server reply code does not equal "200".
* @throws IOException If an I/O error occurs while sending * @throws IOException If an I/O error occurs while sending
@ -480,10 +504,10 @@ public class FTPSClient extends FTPClient {
* Issues the command and parses the response to return the negotiated value. * Issues the command and parses the response to return the negotiated value.
* *
* @param pbsz Protection Buffer Size. * @param pbsz Protection Buffer Size.
* @return the negotiated value.
* @throws SSLException If the server reply code does not equal "200". * @throws SSLException If the server reply code does not equal "200".
* @throws IOException If an I/O error occurs while sending * @throws IOException If an I/O error occurs while sending
* the command. * the command.
* @return the negotiated value.
* @see #execPBSZ(long) * @see #execPBSZ(long)
* @since 3.0 * @since 3.0
*/ */
@ -539,12 +563,12 @@ public class FTPSClient extends FTPClient {
/** /**
* Check the value that can be set in PROT Command value. * Check the value that can be set in PROT Command value.
*
* @param prot Data Channel Protection Level. * @param prot Data Channel Protection Level.
* @return True - A set point is right / False - A set point is not right * @return True - A set point is right / False - A set point is not right
*/ */
private boolean checkPROTValue(String prot) { private boolean checkPROTValue(String prot) {
for (String element : PROT_COMMAND_VALUE) for (String element : PROT_COMMAND_VALUE) {
{
if (element.equals(prot)) { if (element.equals(prot)) {
return true; return true;
} }
@ -556,6 +580,7 @@ public class FTPSClient extends FTPClient {
* Send an FTP command. * Send an FTP command.
* A successful CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} * A successful CCC (Clear Command Channel) command causes the underlying {@link SSLSocket}
* instance to be assigned to a plain {@link Socket} * instance to be assigned to a plain {@link Socket}
*
* @param command The FTP command. * @param command The FTP command.
* @return server reply. * @return server reply.
* @throws IOException If an I/O error occurs while sending the command. * @throws IOException If an I/O error occurs while sending the command.
@ -563,8 +588,7 @@ public class FTPSClient extends FTPClient {
* @see FTP#sendCommand(String) * @see FTP#sendCommand(String)
*/ */
// Would like to remove this method, but that will break any existing clients that are using CCC // Would like to remove this method, but that will break any existing clients that are using CCC
@Override @Override public int sendCommand(String command, String args) throws IOException {
public int sendCommand(String command, String args) throws IOException {
int repCode = super.sendCommand(command, args); int repCode = super.sendCommand(command, args);
/* If CCC is issued, restore socket i/o streams to unsecured versions */ /* If CCC is issued, restore socket i/o streams to unsecured versions */
if (CMD_CCC.equals(command)) { if (CMD_CCC.equals(command)) {
@ -572,11 +596,9 @@ public class FTPSClient extends FTPClient {
_socket_.close(); _socket_.close();
_socket_ = plainSocket; _socket_ = plainSocket;
_controlInput_ = new BufferedReader( _controlInput_ = new BufferedReader(
new InputStreamReader( new InputStreamReader(_socket_.getInputStream(), getControlEncoding()));
_socket_ .getInputStream(), getControlEncoding()));
_controlOutput_ = new BufferedWriter( _controlOutput_ = new BufferedWriter(
new OutputStreamWriter( new OutputStreamWriter(_socket_.getOutputStream(), getControlEncoding()));
_socket_.getOutputStream(), getControlEncoding()));
} else { } else {
throw new SSLException(getReplyString()); throw new SSLException(getReplyString());
} }
@ -587,6 +609,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Returns a socket of the data connection. * Returns a socket of the data connection.
* Wrapped as an {@link SSLSocket}, which carries out handshake processing. * Wrapped as an {@link SSLSocket}, which carries out handshake processing.
*
* @param command The int representation of the FTP command to send. * @param command The int representation of the FTP command to send.
* @param arg The arguments to the FTP command. * @param arg The arguments to the FTP command.
* If this parameter is set to null, then the command is sent with * If this parameter is set to null, then the command is sent with
@ -601,15 +624,14 @@ public class FTPSClient extends FTPClient {
@Override @Override
// Strictly speaking this is not needed, but it works round a Clirr bug // Strictly speaking this is not needed, but it works round a Clirr bug
// So rather than invoke the parent code, we do it here // So rather than invoke the parent code, we do it here
@Deprecated @Deprecated protected Socket _openDataConnection_(int command, String arg) throws IOException {
protected Socket _openDataConnection_(int command, String arg)
throws IOException {
return _openDataConnection_(FTPCommand.getCommand(command), arg); return _openDataConnection_(FTPCommand.getCommand(command), arg);
} }
/** /**
* Returns a socket of the data connection. * Returns a socket of the data connection.
* Wrapped as an {@link SSLSocket}, which carries out handshake processing. * Wrapped as an {@link SSLSocket}, which carries out handshake processing.
*
* @param command The textual representation of the FTP command to send. * @param command The textual representation of the FTP command to send.
* @param arg The arguments to the FTP command. * @param arg The arguments to the FTP command.
* If this parameter is set to null, then the command is sent with * If this parameter is set to null, then the command is sent with
@ -621,13 +643,11 @@ public class FTPSClient extends FTPClient {
* @see FTPClient#_openDataConnection_(int, String) * @see FTPClient#_openDataConnection_(int, String)
* @since 3.2 * @since 3.2
*/ */
@Override @Override protected Socket _openDataConnection_(String command, String arg) throws IOException {
protected Socket _openDataConnection_(String command, String arg)
throws IOException {
Socket socket = super._openDataConnection_(command, arg); Socket socket = super._openDataConnection_(command, arg);
_prepareDataSocket_(socket); _prepareDataSocket_(socket);
if (socket instanceof SSLSocket) { if (socket instanceof SSLSocket) {
SSLSocket sslSocket = (SSLSocket)socket; SSLSocket sslSocket = (SSLSocket) socket;
sslSocket.setUseClientMode(isClientMode); sslSocket.setUseClientMode(isClientMode);
sslSocket.setEnableSessionCreation(isCreation); sslSocket.setEnableSessionCreation(isCreation);
@ -655,12 +675,12 @@ public class FTPSClient extends FTPClient {
* Called by {@link #_openDataConnection_(int, String)} immediately * Called by {@link #_openDataConnection_(int, String)} immediately
* after creating the socket. * after creating the socket.
* The default implementation is a no-op * The default implementation is a no-op
*
* @param socket the socket to set up * @param socket the socket to set up
* @throws IOException on error * @throws IOException on error
* @since 3.1 * @since 3.1
*/ */
protected void _prepareDataSocket_(Socket socket) protected void _prepareDataSocket_(Socket socket) throws IOException {
throws IOException {
} }
/** /**
@ -686,22 +706,23 @@ public class FTPSClient extends FTPClient {
/** /**
* Get the currently configured {@link HostnameVerifier}. * Get the currently configured {@link HostnameVerifier}.
* The verifier is only used on client mode connections. * The verifier is only used on client mode connections.
*
* @return A HostnameVerifier instance. * @return A HostnameVerifier instance.
* @since 3.4 * @since 3.4
*/ */
public HostnameVerifier getHostnameVerifier() public HostnameVerifier getHostnameVerifier() {
{
return hostnameVerifier; return hostnameVerifier;
} }
/** /**
* Override the default {@link HostnameVerifier} to use. * Override the default {@link HostnameVerifier} to use.
* The verifier is only used on client mode connections. * The verifier is only used on client mode connections.
* @param newHostnameVerifier The HostnameVerifier implementation to set or <code>null</code> to disable. *
* @param newHostnameVerifier The HostnameVerifier implementation to set or <code>null</code> to
* disable.
* @since 3.4 * @since 3.4
*/ */
public void setHostnameVerifier(HostnameVerifier newHostnameVerifier) public void setHostnameVerifier(HostnameVerifier newHostnameVerifier) {
{
hostnameVerifier = newHostnameVerifier; hostnameVerifier = newHostnameVerifier;
} }
@ -714,8 +735,7 @@ public class FTPSClient extends FTPClient {
* @return True if enabled, false if not. * @return True if enabled, false if not.
* @since 3.4 * @since 3.4
*/ */
public boolean isEndpointCheckingEnabled() public boolean isEndpointCheckingEnabled() {
{
return tlsEndpointChecking; return tlsEndpointChecking;
} }
@ -725,11 +745,11 @@ public class FTPSClient extends FTPClient {
* *
* This check is only performed on client mode connections. * This check is only performed on client mode connections.
* *
* @param enable Enable automatic endpoint identification checking using the HTTPS algorithm on Java 1.7+. * @param enable Enable automatic endpoint identification checking using the HTTPS algorithm on
* Java 1.7+.
* @since 3.4 * @since 3.4
*/ */
public void setEndpointCheckingEnabled(boolean enable) public void setEndpointCheckingEnabled(boolean enable) {
{
tlsEndpointChecking = enable; tlsEndpointChecking = enable;
} }
@ -740,12 +760,11 @@ public class FTPSClient extends FTPClient {
* Calls {@code setSocketFactory(null)} and {@code setServerSocketFactory(null)} * Calls {@code setSocketFactory(null)} and {@code setServerSocketFactory(null)}
* to reset the factories that may have been changed during the session, * to reset the factories that may have been changed during the session,
* e.g. by {@link #execPROT(String)} * e.g. by {@link #execPROT(String)}
*
* @throws IOException If an error occurs while disconnecting. * @throws IOException If an error occurs while disconnecting.
* @since 3.0 * @since 3.0
*/ */
@Override @Override public void disconnect() throws IOException {
public void disconnect() throws IOException
{
super.disconnect(); super.disconnect();
if (plainSocket != null) { if (plainSocket != null) {
plainSocket.close(); plainSocket.close();
@ -756,131 +775,120 @@ public class FTPSClient extends FTPClient {
/** /**
* Send the AUTH command with the specified mechanism. * Send the AUTH command with the specified mechanism.
*
* @param mechanism The mechanism name to send with the command. * @param mechanism The mechanism name to send with the command.
* @return server reply. * @return server reply.
* @throws IOException If an I/O error occurs while sending * @throws IOException If an I/O error occurs while sending
* the command. * the command.
* @since 3.0 * @since 3.0
*/ */
public int execAUTH(String mechanism) throws IOException public int execAUTH(String mechanism) throws IOException {
{
return sendCommand(CMD_AUTH, mechanism); return sendCommand(CMD_AUTH, mechanism);
} }
/** /**
* Send the ADAT command with the specified authentication data. * Send the ADAT command with the specified authentication data.
*
* @param data The data to send with the command. * @param data The data to send with the command.
* @return server reply. * @return server reply.
* @throws IOException If an I/O error occurs while sending * @throws IOException If an I/O error occurs while sending
* the command. * the command.
* @since 3.0 * @since 3.0
*/ */
public int execADAT(byte[] data) throws IOException public int execADAT(byte[] data) throws IOException {
{ if (data != null) {
if (data != null)
{
return sendCommand(CMD_ADAT, Base64.encodeBase64StringUnChunked(data)); return sendCommand(CMD_ADAT, Base64.encodeBase64StringUnChunked(data));
} } else {
else
{
return sendCommand(CMD_ADAT); return sendCommand(CMD_ADAT);
} }
} }
/** /**
* Send the CCC command to the server. * Send the CCC command to the server.
* The CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be assigned * The CCC (Clear Command Channel) command causes the underlying {@link SSLSocket} instance to be
* assigned
* to a plain {@link Socket} instances * to a plain {@link Socket} instances
*
* @return server reply. * @return server reply.
* @throws IOException If an I/O error occurs while sending * @throws IOException If an I/O error occurs while sending
* the command. * the command.
* @since 3.0 * @since 3.0
*/ */
public int execCCC() throws IOException public int execCCC() throws IOException {
{
int repCode = sendCommand(CMD_CCC); int repCode = sendCommand(CMD_CCC);
// This will be performed by sendCommand(String, String) // This will be performed by sendCommand(String, String)
// if (FTPReply.isPositiveCompletion(repCode)) { // if (FTPReply.isPositiveCompletion(repCode)) {
// _socket_.close(); // _socket_.close();
// _socket_ = plainSocket; // _socket_ = plainSocket;
// _controlInput_ = new BufferedReader( // _controlInput_ = new BufferedReader(
// new InputStreamReader( // new InputStreamReader(
// _socket_.getInputStream(), getControlEncoding())); // _socket_.getInputStream(), getControlEncoding()));
// _controlOutput_ = new BufferedWriter( // _controlOutput_ = new BufferedWriter(
// new OutputStreamWriter( // new OutputStreamWriter(
// _socket_.getOutputStream(), getControlEncoding())); // _socket_.getOutputStream(), getControlEncoding()));
// } // }
return repCode; return repCode;
} }
/** /**
* Send the MIC command with the specified data. * Send the MIC command with the specified data.
*
* @param data The data to send with the command. * @param data The data to send with the command.
* @return server reply. * @return server reply.
* @throws IOException If an I/O error occurs while sending * @throws IOException If an I/O error occurs while sending
* the command. * the command.
* @since 3.0 * @since 3.0
*/ */
public int execMIC(byte[] data) throws IOException public int execMIC(byte[] data) throws IOException {
{ if (data != null) {
if (data != null)
{
return sendCommand(CMD_MIC, Base64.encodeBase64StringUnChunked(data)); return sendCommand(CMD_MIC, Base64.encodeBase64StringUnChunked(data));
} } else {
else
{
return sendCommand(CMD_MIC, ""); // perhaps "=" or just sendCommand(String)? return sendCommand(CMD_MIC, ""); // perhaps "=" or just sendCommand(String)?
} }
} }
/** /**
* Send the CONF command with the specified data. * Send the CONF command with the specified data.
*
* @param data The data to send with the command. * @param data The data to send with the command.
* @return server reply. * @return server reply.
* @throws IOException If an I/O error occurs while sending * @throws IOException If an I/O error occurs while sending
* the command. * the command.
* @since 3.0 * @since 3.0
*/ */
public int execCONF(byte[] data) throws IOException public int execCONF(byte[] data) throws IOException {
{ if (data != null) {
if (data != null)
{
return sendCommand(CMD_CONF, Base64.encodeBase64StringUnChunked(data)); return sendCommand(CMD_CONF, Base64.encodeBase64StringUnChunked(data));
} } else {
else
{
return sendCommand(CMD_CONF, ""); // perhaps "=" or just sendCommand(String)? return sendCommand(CMD_CONF, ""); // perhaps "=" or just sendCommand(String)?
} }
} }
/** /**
* Send the ENC command with the specified data. * Send the ENC command with the specified data.
*
* @param data The data to send with the command. * @param data The data to send with the command.
* @return server reply. * @return server reply.
* @throws IOException If an I/O error occurs while sending * @throws IOException If an I/O error occurs while sending
* the command. * the command.
* @since 3.0 * @since 3.0
*/ */
public int execENC(byte[] data) throws IOException public int execENC(byte[] data) throws IOException {
{ if (data != null) {
if (data != null)
{
return sendCommand(CMD_ENC, Base64.encodeBase64StringUnChunked(data)); return sendCommand(CMD_ENC, Base64.encodeBase64StringUnChunked(data));
} } else {
else
{
return sendCommand(CMD_ENC, ""); // perhaps "=" or just sendCommand(String)? return sendCommand(CMD_ENC, ""); // perhaps "=" or just sendCommand(String)?
} }
} }
/** /**
* Parses the given ADAT response line and base64-decodes the data. * Parses the given ADAT response line and base64-decodes the data.
*
* @param reply The ADAT reply to parse. * @param reply The ADAT reply to parse.
* @return the data in the reply, base64-decoded. * @return the data in the reply, base64-decoded.
* @since 3.0 * @since 3.0
*/ */
public byte[] parseADATReply(String reply) public byte[] parseADATReply(String reply) {
{
if (reply == null) { if (reply == null) {
return null; return null;
} else { } else {
@ -890,6 +898,7 @@ public class FTPSClient extends FTPClient {
/** /**
* Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234 * Extract the data from a reply with a prefix, e.g. PBSZ=1234 => 1234
*
* @param prefix the prefix to find * @param prefix the prefix to find
* @param reply where to find the prefix * @param reply where to find the prefix
* @return the remainder of the string after the prefix, or null if the prefix was not present. * @return the remainder of the string after the prefix, or null if the prefix was not present.
@ -900,26 +909,21 @@ public class FTPSClient extends FTPClient {
return null; return null;
} }
// N.B. Cannot use trim before substring as leading space would affect the offset. // N.B. Cannot use trim before substring as leading space would affect the offset.
return reply.substring(idx+prefix.length()).trim(); return reply.substring(idx + prefix.length()).trim();
} }
// DEPRECATED - for API compatibility only - DO NOT USE // DEPRECATED - for API compatibility only - DO NOT USE
/** @deprecated - not used - may be removed in a future release */ /** @deprecated - not used - may be removed in a future release */
@Deprecated @Deprecated public static String KEYSTORE_ALGORITHM;
public static String KEYSTORE_ALGORITHM;
/** @deprecated - not used - may be removed in a future release */ /** @deprecated - not used - may be removed in a future release */
@Deprecated @Deprecated public static String TRUSTSTORE_ALGORITHM;
public static String TRUSTSTORE_ALGORITHM;
/** @deprecated - not used - may be removed in a future release */ /** @deprecated - not used - may be removed in a future release */
@Deprecated @Deprecated public static String PROVIDER;
public static String PROVIDER;
/** @deprecated - not used - may be removed in a future release */ /** @deprecated - not used - may be removed in a future release */
@Deprecated @Deprecated public static String STORE_TYPE;
public static String STORE_TYPE;
} }
/* kate: indent-width 4; replace-tabs on; */ /* kate: indent-width 4; replace-tabs on; */

@ -19,11 +19,11 @@ package org.apache.commons.net.ftp;
/** /**
* FTPS-specific commands. * FTPS-specific commands.
*
* @since 2.0 * @since 2.0
* @deprecated 3.0 DO NOT USE * @deprecated 3.0 DO NOT USE
*/ */
@Deprecated @Deprecated public final class FTPSCommand {
public final class FTPSCommand {
public static final int AUTH = 0; public static final int AUTH = 0;
public static final int ADAT = 1; public static final int ADAT = 1;
public static final int PBSZ = 2; public static final int PBSZ = 2;
@ -36,7 +36,7 @@ public final class FTPSCommand {
public static final int DATA_CHANNEL_PROTECTION_LEVEL = PROT; public static final int DATA_CHANNEL_PROTECTION_LEVEL = PROT;
public static final int CLEAR_COMMAND_CHANNEL = CCC; public static final int CLEAR_COMMAND_CHANNEL = CCC;
private static final String[] _commands = {"AUTH","ADAT","PBSZ","PROT","CCC"}; private static final String[] _commands = { "AUTH", "ADAT", "PBSZ", "PROT", "CCC" };
/** /**
* Retrieve the FTPS command string corresponding to a specified * Retrieve the FTPS command string corresponding to a specified

@ -27,6 +27,7 @@ import javax.net.ssl.SSLServerSocket;
/** /**
* Server socket factory for FTPS connections. * Server socket factory for FTPS connections.
*
* @since 2.2 * @since 2.2
*/ */
public class FTPSServerSocketFactory extends ServerSocketFactory { public class FTPSServerSocketFactory extends ServerSocketFactory {
@ -39,23 +40,20 @@ public class FTPSServerSocketFactory extends ServerSocketFactory {
} }
// Override the default superclass method // Override the default superclass method
@Override @Override public ServerSocket createServerSocket() throws IOException {
public ServerSocket createServerSocket() throws IOException {
return init(this.context.getServerSocketFactory().createServerSocket()); return init(this.context.getServerSocketFactory().createServerSocket());
} }
@Override @Override public ServerSocket createServerSocket(int port) throws IOException {
public ServerSocket createServerSocket(int port) throws IOException {
return init(this.context.getServerSocketFactory().createServerSocket(port)); return init(this.context.getServerSocketFactory().createServerSocket(port));
} }
@Override @Override public ServerSocket createServerSocket(int port, int backlog) throws IOException {
public ServerSocket createServerSocket(int port, int backlog) throws IOException {
return init(this.context.getServerSocketFactory().createServerSocket(port, backlog)); return init(this.context.getServerSocketFactory().createServerSocket(port, backlog));
} }
@Override @Override public ServerSocket createServerSocket(int port, int backlog, InetAddress ifAddress)
public ServerSocket createServerSocket(int port, int backlog, InetAddress ifAddress) throws IOException { throws IOException {
return init(this.context.getServerSocketFactory().createServerSocket(port, backlog, ifAddress)); return init(this.context.getServerSocketFactory().createServerSocket(port, backlog, ifAddress));
} }

@ -26,7 +26,6 @@ import javax.net.SocketFactory;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
/** /**
*
* Implementation of org.apache.commons.net.SocketFactory * Implementation of org.apache.commons.net.SocketFactory
* *
* @since 2.0 * @since 2.0
@ -40,18 +39,16 @@ public class FTPSSocketFactory extends SocketFactory {
} }
// Override the default implementation // Override the default implementation
@Override @Override public Socket createSocket() throws IOException {
public Socket createSocket() throws IOException{
return this.context.getSocketFactory().createSocket(); return this.context.getSocketFactory().createSocket();
} }
@Override @Override public Socket createSocket(String address, int port)
public Socket createSocket(String address, int port) throws UnknownHostException, IOException { throws UnknownHostException, IOException {
return this.context.getSocketFactory().createSocket(address, port); return this.context.getSocketFactory().createSocket(address, port);
} }
@Override @Override public Socket createSocket(InetAddress address, int port) throws IOException {
public Socket createSocket(InetAddress address, int port) throws IOException {
return this.context.getSocketFactory().createSocket(address, port); return this.context.getSocketFactory().createSocket(address, port);
} }
@ -62,51 +59,58 @@ public class FTPSSocketFactory extends SocketFactory {
} }
@Override @Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort)
throws IOException {
return this.context.getSocketFactory().createSocket(address, port, localAddress, localPort); return this.context.getSocketFactory().createSocket(address, port, localAddress, localPort);
} }
// DEPRECATED METHODS - for API compatibility only - DO NOT USE // DEPRECATED METHODS - for API compatibility only - DO NOT USE
/** @param port the port /**
* @param port the port
* @return the socket * @return the socket
* @throws IOException on error * @throws IOException on error
* @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int) instead} */ * @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int) instead}
@Deprecated */
public java.net.ServerSocket createServerSocket(int port) throws IOException { @Deprecated public java.net.ServerSocket createServerSocket(int port) throws IOException {
return this.init(this.context.getServerSocketFactory().createServerSocket(port)); return this.init(this.context.getServerSocketFactory().createServerSocket(port));
} }
/** @param port the port /**
* @param port the port
* @param backlog the backlog * @param backlog the backlog
* @return the socket * @return the socket
* @throws IOException on error * @throws IOException on error
* @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int, int) instead} */ * @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int, int) instead}
@Deprecated */
public java.net.ServerSocket createServerSocket(int port, int backlog) throws IOException { @Deprecated public java.net.ServerSocket createServerSocket(int port, int backlog)
throws IOException {
return this.init(this.context.getServerSocketFactory().createServerSocket(port, backlog)); return this.init(this.context.getServerSocketFactory().createServerSocket(port, backlog));
} }
/** @param port the port /**
* @param port the port
* @param backlog the backlog * @param backlog the backlog
* @param ifAddress the interface * @param ifAddress the interface
* @return the socket * @return the socket
* @throws IOException on error * @throws IOException on error
* @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int, int, InetAddress) instead} */ * @deprecated (2.2) use {@link FTPSServerSocketFactory#createServerSocket(int, int, InetAddress)
@Deprecated * instead}
public java.net.ServerSocket createServerSocket(int port, int backlog, InetAddress ifAddress) throws IOException { */
return this.init(this.context.getServerSocketFactory().createServerSocket(port, backlog, ifAddress)); @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 /**
* @param socket the socket
* @return the socket * @return the socket
* @throws IOException on error * @throws IOException on error
* @deprecated (2.2) use {@link FTPSServerSocketFactory#init(java.net.ServerSocket)} */ * @deprecated (2.2) use {@link FTPSServerSocketFactory#init(java.net.ServerSocket)}
@Deprecated */
public java.net.ServerSocket init(java.net.ServerSocket socket) throws IOException { @Deprecated public java.net.ServerSocket init(java.net.ServerSocket socket) throws IOException {
((javax.net.ssl.SSLServerSocket) socket).setUseClientMode(true); ((javax.net.ssl.SSLServerSocket) socket).setUseClientMode(true);
return socket; return socket;
} }
} }

@ -24,37 +24,30 @@ import javax.net.ssl.X509TrustManager;
/** /**
* Do not use. * Do not use.
*
* @since 2.0 * @since 2.0
* @deprecated 3.0 use * @deprecated 3.0 use
* {@link org.apache.commons.net.util.TrustManagerUtils#getValidateServerCertificateTrustManager() * {@link org.apache.commons.net.util.TrustManagerUtils#getValidateServerCertificateTrustManager()
* TrustManagerUtils#getValidateServerCertificateTrustManager()} instead * TrustManagerUtils#getValidateServerCertificateTrustManager()} instead
*/ */
@Deprecated @Deprecated public class FTPSTrustManager implements X509TrustManager {
public class FTPSTrustManager implements X509TrustManager private static final X509Certificate[] EMPTY_X509CERTIFICATE_ARRAY = new X509Certificate[] {};
{
private static final X509Certificate[] EMPTY_X509CERTIFICATE_ARRAY = new X509Certificate[]{};
/** /**
* No-op * No-op
*/ */
@Override @Override public void checkClientTrusted(X509Certificate[] certificates, String authType) {
public void checkClientTrusted(X509Certificate[] certificates, String authType)
{
return; return;
} }
@Override @Override public void checkServerTrusted(X509Certificate[] certificates, String authType)
public void checkServerTrusted(X509Certificate[] certificates, String authType) throws CertificateException throws CertificateException {
{ for (X509Certificate certificate : certificates) {
for (X509Certificate certificate : certificates)
{
certificate.checkValidity(); certificate.checkValidity();
} }
} }
@Override @Override public X509Certificate[] getAcceptedIssuers() {
public X509Certificate[] getAcceptedIssuers()
{
return EMPTY_X509CERTIFICATE_ARRAY; return EMPTY_X509CERTIFICATE_ARRAY;
} }
} }

@ -0,0 +1,33 @@
/*
* 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 org.apache.commons.net.ftp;
import org.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);
}

@ -28,37 +28,27 @@ import org.apache.commons.net.ftp.FTPFileEntryParserImpl;
* If the cached parser wont match due to the server changed the dirstyle, * If the cached parser wont match due to the server changed the dirstyle,
* a new matching parser will be searched. * a new matching parser will be searched.
*/ */
public class CompositeFileEntryParser extends FTPFileEntryParserImpl public class CompositeFileEntryParser extends FTPFileEntryParserImpl {
{
private final FTPFileEntryParser[] ftpFileEntryParsers; private final FTPFileEntryParser[] ftpFileEntryParsers;
private FTPFileEntryParser cachedFtpFileEntryParser; private FTPFileEntryParser cachedFtpFileEntryParser;
public CompositeFileEntryParser(FTPFileEntryParser[] ftpFileEntryParsers) public CompositeFileEntryParser(FTPFileEntryParser[] ftpFileEntryParsers) {
{
super(); super();
this.cachedFtpFileEntryParser = null; this.cachedFtpFileEntryParser = null;
this.ftpFileEntryParsers = ftpFileEntryParsers; this.ftpFileEntryParsers = ftpFileEntryParsers;
} }
@Override @Override public FTPFile parseFTPEntry(String listEntry) {
public FTPFile parseFTPEntry(String listEntry) if (cachedFtpFileEntryParser != null) {
{
if (cachedFtpFileEntryParser != null)
{
FTPFile matched = cachedFtpFileEntryParser.parseFTPEntry(listEntry); FTPFile matched = cachedFtpFileEntryParser.parseFTPEntry(listEntry);
if (matched != null) if (matched != null) {
{
return matched; return matched;
} }
} } else {
else for (FTPFileEntryParser ftpFileEntryParser : ftpFileEntryParsers) {
{
for (FTPFileEntryParser ftpFileEntryParser : ftpFileEntryParsers)
{
FTPFile matched = ftpFileEntryParser.parseFTPEntry(listEntry); FTPFile matched = ftpFileEntryParser.parseFTPEntry(listEntry);
if (matched != null) if (matched != null) {
{
cachedFtpFileEntryParser = ftpFileEntryParser; cachedFtpFileEntryParser = ftpFileEntryParser;
return matched; return matched;
} }

@ -23,7 +23,6 @@ import java.util.Calendar;
import org.apache.commons.net.ftp.Configurable; import org.apache.commons.net.ftp.Configurable;
import org.apache.commons.net.ftp.FTPClientConfig; import org.apache.commons.net.ftp.FTPClientConfig;
/** /**
* <p> * <p>
* This abstract class implements the common timestamp parsing * This abstract class implements the common timestamp parsing
@ -38,34 +37,33 @@ import org.apache.commons.net.ftp.FTPClientConfig;
* *
* @since 1.4 * @since 1.4
*/ */
public abstract class ConfigurableFTPFileEntryParserImpl public abstract class ConfigurableFTPFileEntryParserImpl extends RegexFTPFileEntryParserImpl
extends RegexFTPFileEntryParserImpl implements Configurable {
implements Configurable
{
private final FTPTimestampParser timestampParser; private final FTPTimestampParser timestampParser;
/** /**
* constructor for this abstract class. * constructor for this abstract class.
*
* @param regex Regular expression used main parsing of the * @param regex Regular expression used main parsing of the
* file listing. * file listing.
*/ */
public ConfigurableFTPFileEntryParserImpl(String regex) public ConfigurableFTPFileEntryParserImpl(String regex) {
{
super(regex); super(regex);
this.timestampParser = new FTPTimestampParserImpl(); this.timestampParser = new FTPTimestampParserImpl();
} }
/** /**
* constructor for this abstract class. * constructor for this abstract class.
*
* @param regex Regular expression used main parsing of the * @param regex Regular expression used main parsing of the
* file listing. * file listing.
* @param flags the flags to apply, see * @param flags the flags to apply, see
* {@link java.util.regex.Pattern#compile(String, int) Pattern#compile(String, int)}. Use 0 for none. * {@link java.util.regex.Pattern#compile(String, int) Pattern#compile(String, int)}. Use 0 for
* none.
* @since 3.4 * @since 3.4
*/ */
public ConfigurableFTPFileEntryParserImpl(String regex, int flags) public ConfigurableFTPFileEntryParserImpl(String regex, int flags) {
{
super(regex, flags); super(regex, flags);
this.timestampParser = new FTPTimestampParserImpl(); this.timestampParser = new FTPTimestampParserImpl();
} }
@ -85,7 +83,6 @@ implements Configurable
return this.timestampParser.parseTimestamp(timestampStr); return this.timestampParser.parseTimestamp(timestampStr);
} }
/** /**
* Implementation of the {@link Configurable Configurable} * Implementation of the {@link Configurable Configurable}
* interface. Configures this parser by delegating to the * interface. Configures this parser by delegating to the
@ -98,9 +95,7 @@ implements Configurable
* If it is null, a default configuration defined by * If it is null, a default configuration defined by
* each concrete subclass is used instead. * each concrete subclass is used instead.
*/ */
@Override @Override public void configure(FTPClientConfig config) {
public void configure(FTPClientConfig config)
{
if (this.timestampParser instanceof Configurable) { if (this.timestampParser instanceof Configurable) {
FTPClientConfig defaultCfg = getDefaultConfiguration(); FTPClientConfig defaultCfg = getDefaultConfiguration();
if (config != null) { if (config != null) {
@ -110,9 +105,9 @@ implements Configurable
if (null == config.getRecentDateFormatStr()) { if (null == config.getRecentDateFormatStr()) {
config.setRecentDateFormatStr(defaultCfg.getRecentDateFormatStr()); config.setRecentDateFormatStr(defaultCfg.getRecentDateFormatStr());
} }
((Configurable)this.timestampParser).configure(config); ((Configurable) this.timestampParser).configure(config);
} else { } else {
((Configurable)this.timestampParser).configure(defaultCfg); ((Configurable) this.timestampParser).configure(defaultCfg);
} }
} }
} }
@ -122,6 +117,7 @@ implements Configurable
* a default configuration to be used when that subclass is * a default configuration to be used when that subclass is
* instantiated without a {@link FTPClientConfig FTPClientConfig} * instantiated without a {@link FTPClientConfig FTPClientConfig}
* parameter being specified. * parameter being specified.
*
* @return the default configuration for the subclass. * @return the default configuration for the subclass.
*/ */
protected abstract FTPClientConfig getDefaultConfiguration(); protected abstract FTPClientConfig getDefaultConfiguration();

@ -23,7 +23,6 @@ import org.apache.commons.net.ftp.Configurable;
import org.apache.commons.net.ftp.FTPClientConfig; import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFileEntryParser; import org.apache.commons.net.ftp.FTPFileEntryParser;
/** /**
* This is the default implementation of the * This is the default implementation of the
* FTPFileEntryParserFactory interface. This is the * FTPFileEntryParserFactory interface. This is the
@ -34,14 +33,14 @@ import org.apache.commons.net.ftp.FTPFileEntryParser;
* @see org.apache.commons.net.ftp.FTPClient#listFiles * @see org.apache.commons.net.ftp.FTPClient#listFiles
* @see org.apache.commons.net.ftp.FTPClient#setParserFactory * @see org.apache.commons.net.ftp.FTPClient#setParserFactory
*/ */
public class DefaultFTPFileEntryParserFactory public class DefaultFTPFileEntryParserFactory implements FTPFileEntryParserFactory {
implements FTPFileEntryParserFactory
{
// Match a plain Java Identifier // Match a plain Java Identifier
private static final String JAVA_IDENTIFIER = "\\p{javaJavaIdentifierStart}(\\p{javaJavaIdentifierPart})*"; 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. // 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; private static final String JAVA_QUALIFIED_NAME =
"(" + JAVA_IDENTIFIER + "\\.)+" + JAVA_IDENTIFIER;
// Create the pattern, as it will be reused many times // Create the pattern, as it will be reused many times
private static final Pattern JAVA_QUALIFIED_NAME_PATTERN = Pattern.compile(JAVA_QUALIFIED_NAME); private static final Pattern JAVA_QUALIFIED_NAME_PATTERN = Pattern.compile(JAVA_QUALIFIED_NAME);
@ -85,9 +84,7 @@ public class DefaultFTPFileEntryParserFactory
* the supplied key into an FTPFileEntryParser. * the supplied key into an FTPFileEntryParser.
* @see FTPFileEntryParser * @see FTPFileEntryParser
*/ */
@Override @Override public FTPFileEntryParser createFileEntryParser(String key) {
public FTPFileEntryParser createFileEntryParser(String key)
{
if (key == null) { if (key == null) {
throw new ParserInitializationException("Parser key cannot be null"); throw new ParserInitializationException("Parser key cannot be null");
} }
@ -100,8 +97,7 @@ public class DefaultFTPFileEntryParserFactory
// Is the key a possible class name? // Is the key a possible class name?
if (JAVA_QUALIFIED_NAME_PATTERN.matcher(key).matches()) { if (JAVA_QUALIFIED_NAME_PATTERN.matcher(key).matches()) {
try try {
{
Class<?> parserClass = Class.forName(key); Class<?> parserClass = Class.forName(key);
try { try {
parser = (FTPFileEntryParser) parserClass.newInstance(); parser = (FTPFileEntryParser) parserClass.newInstance();
@ -121,58 +117,38 @@ public class DefaultFTPFileEntryParserFactory
if (parser == null) { // Now try for aliases if (parser == null) { // Now try for aliases
String ukey = key.toUpperCase(java.util.Locale.ENGLISH); String ukey = key.toUpperCase(java.util.Locale.ENGLISH);
if (ukey.indexOf(FTPClientConfig.SYST_UNIX_TRIM_LEADING) >= 0) if (ukey.indexOf(FTPClientConfig.SYST_UNIX_TRIM_LEADING) >= 0) {
{
parser = new UnixFTPEntryParser(config, true); parser = new UnixFTPEntryParser(config, true);
} }
// must check this after SYST_UNIX_TRIM_LEADING as it is a substring of it // must check this after SYST_UNIX_TRIM_LEADING as it is a substring of it
else if (ukey.indexOf(FTPClientConfig.SYST_UNIX) >= 0) else if (ukey.indexOf(FTPClientConfig.SYST_UNIX) >= 0) {
{
parser = new UnixFTPEntryParser(config, false); parser = new UnixFTPEntryParser(config, false);
} } else if (ukey.indexOf(FTPClientConfig.SYST_VMS) >= 0) {
else if (ukey.indexOf(FTPClientConfig.SYST_VMS) >= 0)
{
parser = new VMSVersioningFTPEntryParser(config); parser = new VMSVersioningFTPEntryParser(config);
} } else if (ukey.indexOf(FTPClientConfig.SYST_NT) >= 0) {
else if (ukey.indexOf(FTPClientConfig.SYST_NT) >= 0)
{
parser = createNTFTPEntryParser(config); parser = createNTFTPEntryParser(config);
} } else if (ukey.indexOf(FTPClientConfig.SYST_OS2) >= 0) {
else if (ukey.indexOf(FTPClientConfig.SYST_OS2) >= 0)
{
parser = new OS2FTPEntryParser(config); parser = new OS2FTPEntryParser(config);
} } else if (ukey.indexOf(FTPClientConfig.SYST_OS400) >= 0
else if (ukey.indexOf(FTPClientConfig.SYST_OS400) >= 0 || || ukey.indexOf(FTPClientConfig.SYST_AS400) >= 0) {
ukey.indexOf(FTPClientConfig.SYST_AS400) >= 0)
{
parser = createOS400FTPEntryParser(config); parser = createOS400FTPEntryParser(config);
} } else if (ukey.indexOf(FTPClientConfig.SYST_MVS) >= 0) {
else if (ukey.indexOf(FTPClientConfig.SYST_MVS) >= 0)
{
parser = new MVSFTPEntryParser(); // Does not currently support config parameter parser = new MVSFTPEntryParser(); // Does not currently support config parameter
} } else if (ukey.indexOf(FTPClientConfig.SYST_NETWARE) >= 0) {
else if (ukey.indexOf(FTPClientConfig.SYST_NETWARE) >= 0)
{
parser = new NetwareFTPEntryParser(config); parser = new NetwareFTPEntryParser(config);
} } else if (ukey.indexOf(FTPClientConfig.SYST_MACOS_PETER) >= 0) {
else if (ukey.indexOf(FTPClientConfig.SYST_MACOS_PETER) >= 0)
{
parser = new MacOsPeterFTPEntryParser(config); parser = new MacOsPeterFTPEntryParser(config);
} } else if (ukey.indexOf(FTPClientConfig.SYST_L8) >= 0) {
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. // L8 normally means Unix, but move it to the end for some L8 systems that aren't.
// This check should be last! // This check should be last!
parser = new UnixFTPEntryParser(config); parser = new UnixFTPEntryParser(config);
} } else {
else
{
throw new ParserInitializationException("Unknown parser type: " + key); throw new ParserInitializationException("Unknown parser type: " + key);
} }
} }
if (parser instanceof Configurable) { if (parser instanceof Configurable) {
((Configurable)parser).configure(config); ((Configurable) parser).configure(config);
} }
return parser; return parser;
} }
@ -189,31 +165,25 @@ public class DefaultFTPFileEntryParserFactory
* where the user knows that the server uses a non-default configuration * where the user knows that the server uses a non-default configuration
* and knows what that configuration is. * and knows what that configuration is.
* </p> * </p>
*
* @param config A {@link FTPClientConfig FTPClientConfig} * @param config A {@link FTPClientConfig FTPClientConfig}
* used to configure the parser created * used to configure the parser created
*
* @return the @link FTPFileEntryParser FTPFileEntryParser} so created. * @return the @link FTPFileEntryParser FTPFileEntryParser} so created.
* @throws ParserInitializationException * @throws ParserInitializationException Thrown on any exception in instantiation
* Thrown on any exception in instantiation
* @throws NullPointerException if {@code config} is {@code null} * @throws NullPointerException if {@code config} is {@code null}
* @since 1.4 * @since 1.4
*/ */
@Override @Override public FTPFileEntryParser createFileEntryParser(FTPClientConfig config)
public FTPFileEntryParser createFileEntryParser(FTPClientConfig config) throws ParserInitializationException {
throws ParserInitializationException
{
String key = config.getServerSystemKey(); String key = config.getServerSystemKey();
return createFileEntryParser(key, config); return createFileEntryParser(key, config);
} }
public FTPFileEntryParser createUnixFTPEntryParser() {
public FTPFileEntryParser createUnixFTPEntryParser()
{
return new UnixFTPEntryParser(); return new UnixFTPEntryParser();
} }
public FTPFileEntryParser createVMSVersioningFTPEntryParser() public FTPFileEntryParser createVMSVersioningFTPEntryParser() {
{
return new VMSVersioningFTPEntryParser(); return new VMSVersioningFTPEntryParser();
} }
@ -221,8 +191,7 @@ public class DefaultFTPFileEntryParserFactory
return new NetwareFTPEntryParser(); return new NetwareFTPEntryParser();
} }
public FTPFileEntryParser createNTFTPEntryParser() public FTPFileEntryParser createNTFTPEntryParser() {
{
return createNTFTPEntryParser(null); return createNTFTPEntryParser(null);
} }
@ -230,34 +199,29 @@ public class DefaultFTPFileEntryParserFactory
* Creates an NT FTP parser: if the config exists, and the system key equals * 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, * {@link FTPClientConfig.SYST_NT} then a plain {@link NTFTPEntryParser} is used,
* otherwise a composite of {@link NTFTPEntryParser} and {@link UnixFTPEntryParser} is used. * otherwise a composite of {@link NTFTPEntryParser} and {@link UnixFTPEntryParser} is used.
*
* @param config the config to use, may be {@code null} * @param config the config to use, may be {@code null}
* @return the parser * @return the parser
*/ */
private FTPFileEntryParser createNTFTPEntryParser(FTPClientConfig config) private FTPFileEntryParser createNTFTPEntryParser(FTPClientConfig config) {
{ if (config != null && FTPClientConfig.SYST_NT.equals(config.getServerSystemKey())) {
if (config != null && FTPClientConfig.SYST_NT.equals(
config.getServerSystemKey()))
{
return new NTFTPEntryParser(config); return new NTFTPEntryParser(config);
} else { } else {
// clone the config as it may be changed by the parsers (NET-602) // clone the config as it may be changed by the parsers (NET-602)
final FTPClientConfig config2 = (config != null) ? new FTPClientConfig(config) : null; final FTPClientConfig config2 = (config != null) ? new FTPClientConfig(config) : null;
return new CompositeFileEntryParser(new FTPFileEntryParser[] return new CompositeFileEntryParser(new FTPFileEntryParser[] {
{ new NTFTPEntryParser(config), new UnixFTPEntryParser(config2,
new NTFTPEntryParser(config), config2 != null && FTPClientConfig.SYST_UNIX_TRIM_LEADING.equals(
new UnixFTPEntryParser(config2, config2.getServerSystemKey()))
config2 != null && FTPClientConfig.SYST_UNIX_TRIM_LEADING.equals(config2.getServerSystemKey()))
}); });
} }
} }
public FTPFileEntryParser createOS2FTPEntryParser() public FTPFileEntryParser createOS2FTPEntryParser() {
{
return new OS2FTPEntryParser(); return new OS2FTPEntryParser();
} }
public FTPFileEntryParser createOS400FTPEntryParser() public FTPFileEntryParser createOS400FTPEntryParser() {
{
return createOS400FTPEntryParser(null); return createOS400FTPEntryParser(null);
} }
@ -265,31 +229,26 @@ public class DefaultFTPFileEntryParserFactory
* Creates an OS400 FTP parser: if the config exists, and the system key equals * 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, * {@link FTPClientConfig.SYST_OS400} then a plain {@link OS400FTPEntryParser} is used,
* otherwise a composite of {@link OS400FTPEntryParser} and {@link UnixFTPEntryParser} is used. * otherwise a composite of {@link OS400FTPEntryParser} and {@link UnixFTPEntryParser} is used.
*
* @param config the config to use, may be {@code null} * @param config the config to use, may be {@code null}
* @return the parser * @return the parser
*/ */
private FTPFileEntryParser createOS400FTPEntryParser(FTPClientConfig config) private FTPFileEntryParser createOS400FTPEntryParser(FTPClientConfig config) {
{ if (config != null && FTPClientConfig.SYST_OS400.equals(config.getServerSystemKey())) {
if (config != null &&
FTPClientConfig.SYST_OS400.equals(config.getServerSystemKey()))
{
return new OS400FTPEntryParser(config); return new OS400FTPEntryParser(config);
} else { } else {
// clone the config as it may be changed by the parsers (NET-602) // clone the config as it may be changed by the parsers (NET-602)
final FTPClientConfig config2 = (config != null) ? new FTPClientConfig(config) : null; final FTPClientConfig config2 = (config != null) ? new FTPClientConfig(config) : null;
return new CompositeFileEntryParser(new FTPFileEntryParser[] return new CompositeFileEntryParser(new FTPFileEntryParser[] {
{ new OS400FTPEntryParser(config), new UnixFTPEntryParser(config2,
new OS400FTPEntryParser(config), config2 != null && FTPClientConfig.SYST_UNIX_TRIM_LEADING.equals(
new UnixFTPEntryParser(config2, config2.getServerSystemKey()))
config2 != null && FTPClientConfig.SYST_UNIX_TRIM_LEADING.equals(config2.getServerSystemKey()))
}); });
} }
} }
public FTPFileEntryParser createMVSEntryParser() public FTPFileEntryParser createMVSEntryParser() {
{
return new MVSFTPEntryParser(); return new MVSFTPEntryParser();
} }
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp.parser; package org.apache.commons.net.ftp.parser;
import java.util.Calendar; import java.util.Calendar;
import org.apache.commons.net.ftp.FTPFile; import org.apache.commons.net.ftp.FTPFile;
@ -29,19 +30,18 @@ import org.apache.commons.net.ftp.FTPFile;
* DefaultFTPParserFactory by classname. It will not be chosen * DefaultFTPParserFactory by classname. It will not be chosen
* by the autodetection scheme. * by the autodetection scheme.
* </B> * </B>
*
* @version $Id: EnterpriseUnixFTPEntryParser.java 1741829 2016-05-01 00:24:44Z sebb $ * @version $Id: EnterpriseUnixFTPEntryParser.java 1741829 2016-05-01 00:24:44Z sebb $
* @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
* @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
*/ */
public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl {
{
/** /**
* months abbreviations looked for by this parser. Also used * months abbreviations looked for by this parser. Also used
* to determine <b>which</b> month has been matched by the parser. * to determine <b>which</b> month has been matched by the parser.
*/ */
private static final String MONTHS = private static final String MONTHS = "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)";
"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)";
/** /**
* this is the regular expression used by this parser. * this is the regular expression used by this parser.
@ -49,15 +49,23 @@ public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl
private static final String REGEX = 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])"
+ "([\\-]|[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*"
+ "(\\S+)\\s*" // 13 // 12
+ "(\\S*)\\s*" // 14 user + "(\\S+)\\s*"
+ "(\\d*)\\s*" // 15 group // 13
+ "(\\d*)\\s*" // 16 filesize + "(\\S*)\\s*"
+ MONTHS // 17 month // 14 user
+ "\\s*" // TODO should the space be optional? + "(\\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 // TODO \\d* should be \\d? surely ? Otherwise 01111 is allowed
+ "((?:[012]\\d*)|(?:3[01]))\\s*" // 18 date [012]\d* or 3[01] + "((?:[012]\\d*)|(?:3[01]))\\s*"
// 18 date [012]\d* or 3[01]
+ "((\\d\\d\\d\\d)|((?:[01]\\d)|(?:2[0123])):([012345]\\d))\\s" + "((\\d\\d\\d\\d)|((?:[01]\\d)|(?:2[0123])):([012345]\\d))\\s"
// 20 \d\d\d\d = year OR // 20 \d\d\d\d = year OR
// 21 [01]\d or 2[0123] hour + ':' // 21 [01]\d or 2[0123] hour + ':'
@ -66,10 +74,8 @@ public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl
/** /**
* The sole constructor for a EnterpriseUnixFTPEntryParser object. * The sole constructor for a EnterpriseUnixFTPEntryParser object.
*
*/ */
public EnterpriseUnixFTPEntryParser() public EnterpriseUnixFTPEntryParser() {
{
super(REGEX); super(REGEX);
} }
@ -83,15 +89,12 @@ public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl
* @param entry A line of text from the file listing * @param entry A line of text from the file listing
* @return An FTPFile instance corresponding to the supplied entry * @return An FTPFile instance corresponding to the supplied entry
*/ */
@Override @Override public FTPFile parseFTPEntry(String entry) {
public FTPFile parseFTPEntry(String entry)
{
FTPFile file = new FTPFile(); FTPFile file = new FTPFile();
file.setRawListing(entry); file.setRawListing(entry);
if (matches(entry)) if (matches(entry)) {
{
String usr = group(14); String usr = group(14);
String grp = group(15); String grp = group(15);
String filesize = group(16); String filesize = group(16);
@ -105,12 +108,9 @@ public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl
file.setType(FTPFile.FILE_TYPE); file.setType(FTPFile.FILE_TYPE);
file.setUser(usr); file.setUser(usr);
file.setGroup(grp); file.setGroup(grp);
try try {
{
file.setSize(Long.parseLong(filesize)); file.setSize(Long.parseLong(filesize));
} } catch (NumberFormatException e) {
catch (NumberFormatException e)
{
// intentionally do nothing // intentionally do nothing
} }
@ -123,25 +123,20 @@ public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl
int pos = MONTHS.indexOf(mo); int pos = MONTHS.indexOf(mo);
int month = pos / 4; int month = pos / 4;
final int missingUnit; // the first missing unit final int missingUnit; // the first missing unit
try try {
{
if (yr != null) if (yr != null) {
{
// it's a year; there are no hours and minutes // it's a year; there are no hours and minutes
cal.set(Calendar.YEAR, Integer.parseInt(yr)); cal.set(Calendar.YEAR, Integer.parseInt(yr));
missingUnit = Calendar.HOUR_OF_DAY; missingUnit = Calendar.HOUR_OF_DAY;
} } else {
else
{
// it must be hour/minute or we wouldn't have matched // it must be hour/minute or we wouldn't have matched
missingUnit = Calendar.SECOND; missingUnit = Calendar.SECOND;
int year = cal.get(Calendar.YEAR); int year = cal.get(Calendar.YEAR);
// if the month we're reading is greater than now, it must // if the month we're reading is greater than now, it must
// be last year // be last year
if (cal.get(Calendar.MONTH) < month) if (cal.get(Calendar.MONTH) < month) {
{
year--; year--;
} }
cal.set(Calendar.YEAR, year); cal.set(Calendar.YEAR, year);
@ -152,9 +147,7 @@ public class EnterpriseUnixFTPEntryParser extends RegexFTPFileEntryParserImpl
cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(da)); cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(da));
cal.clear(missingUnit); cal.clear(missingUnit);
file.setTimestamp(cal); file.setTimestamp(cal);
} } catch (NumberFormatException e) {
catch (NumberFormatException e)
{
// do nothing, date will be uninitialized // do nothing, date will be uninitialized
} }
file.setName(name); file.setName(name);

@ -16,15 +16,16 @@
*/ */
package org.apache.commons.net.ftp.parser; package org.apache.commons.net.ftp.parser;
import org.apache.commons.net.ftp.FTPClientConfig; import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFileEntryParser; import org.apache.commons.net.ftp.FTPFileEntryParser;
/** /**
* The interface describes a factory for creating FTPFileEntryParsers. * The interface describes a factory for creating FTPFileEntryParsers.
*
* @since 1.2 * @since 1.2
*/ */
public interface FTPFileEntryParserFactory public interface FTPFileEntryParserFactory {
{
/** /**
* Implementation should be a method that decodes the * Implementation should be a method that decodes the
* supplied key and creates an object implementing the * supplied key and creates an object implementing the
@ -32,16 +33,13 @@ public interface FTPFileEntryParserFactory
* *
* @param key A string that somehow identifies an * @param key A string that somehow identifies an
* FTPFileEntryParser to be created. * FTPFileEntryParser to be created.
*
* @return the FTPFileEntryParser created. * @return the FTPFileEntryParser created.
* @throws ParserInitializationException * @throws ParserInitializationException Thrown on any exception in instantiation
* Thrown on any exception in instantiation
*/ */
public FTPFileEntryParser createFileEntryParser(String key) public FTPFileEntryParser createFileEntryParser(String key) throws ParserInitializationException;
throws ParserInitializationException;
/** /**
*<p> * <p>
* Implementation should be a method that extracts * Implementation should be a method that extracts
* a key from the supplied {@link FTPClientConfig FTPClientConfig} * a key from the supplied {@link FTPClientConfig FTPClientConfig}
* parameter and creates an object implementing the * parameter and creates an object implementing the
@ -56,13 +54,10 @@ public interface FTPFileEntryParserFactory
* *
* @param config A {@link FTPClientConfig FTPClientConfig} * @param config A {@link FTPClientConfig FTPClientConfig}
* used to configure the parser created * used to configure the parser created
*
* @return the @link FTPFileEntryParser FTPFileEntryParser} so created. * @return the @link FTPFileEntryParser FTPFileEntryParser} so created.
* @throws ParserInitializationException * @throws ParserInitializationException Thrown on any exception in instantiation
* Thrown on any exception in instantiation
* @since 1.4 * @since 1.4
*/ */
public FTPFileEntryParser createFileEntryParser(FTPClientConfig config) public FTPFileEntryParser createFileEntryParser(FTPClientConfig config)
throws ParserInitializationException; throws ParserInitializationException;
} }

@ -23,6 +23,7 @@ import java.util.Calendar;
/** /**
* This interface specifies the concept of parsing an FTP server's * This interface specifies the concept of parsing an FTP server's
* timestamp. * timestamp.
*
* @since 1.4 * @since 1.4
*/ */
public interface FTPTimestampParser { public interface FTPTimestampParser {
@ -40,6 +41,7 @@ public interface FTPTimestampParser {
* Parses the supplied datestamp parameter. This parameter typically would * Parses the supplied datestamp parameter. This parameter typically would
* have been pulled from a longer FTP listing via the regular expression * have been pulled from a longer FTP listing via the regular expression
* mechanism * mechanism
*
* @param timestampStr - the timestamp portion of the FTP directory listing * @param timestampStr - the timestamp portion of the FTP directory listing
* to be parsed * to be parsed
* @return a <code>java.util.Calendar</code> object initialized to the date * @return a <code>java.util.Calendar</code> object initialized to the date
@ -48,5 +50,4 @@ public interface FTPTimestampParser {
* the implementor can parse the input. * the implementor can parse the input.
*/ */
public Calendar parseTimestamp(String timestampStr) throws ParseException; public Calendar parseTimestamp(String timestampStr) throws ParseException;
} }

@ -36,10 +36,7 @@ import org.apache.commons.net.ftp.FTPClientConfig;
* @see ConfigurableFTPFileEntryParserImpl * @see ConfigurableFTPFileEntryParserImpl
* @since 1.4 * @since 1.4
*/ */
public class FTPTimestampParserImpl implements public class FTPTimestampParserImpl implements FTPTimestampParser, Configurable {
FTPTimestampParser, Configurable
{
/** The date format for all dates, except possibly recent dates. Assumed to include the year. */ /** The date format for all dates, except possibly recent dates. Assumed to include the year. */
private SimpleDateFormat defaultDateFormat; private SimpleDateFormat defaultDateFormat;
@ -66,13 +63,9 @@ public class FTPTimestampParserImpl implements
* e.g. for MINUTE it would clear MILLISECOND and SECOND * e.g. for MINUTE it would clear MILLISECOND and SECOND
*/ */
private static final int[] CALENDAR_UNITS = { private static final int[] CALENDAR_UNITS = {
Calendar.MILLISECOND, Calendar.MILLISECOND, Calendar.SECOND, Calendar.MINUTE, Calendar.HOUR_OF_DAY,
Calendar.SECOND, Calendar.DAY_OF_MONTH, Calendar.MONTH, Calendar.YEAR
Calendar.MINUTE, };
Calendar.HOUR_OF_DAY,
Calendar.DAY_OF_MONTH,
Calendar.MONTH,
Calendar.YEAR};
/* /*
* Return the index to the array representing the least significant * Return the index to the array representing the least significant
@ -83,11 +76,11 @@ public class FTPTimestampParserImpl implements
if (dateFormat == null) { if (dateFormat == null) {
return 0; return 0;
} }
final String FORMAT_CHARS="SsmHdM"; final String FORMAT_CHARS = "SsmHdM";
final String pattern = dateFormat.toPattern(); final String pattern = dateFormat.toPattern();
for(char ch : FORMAT_CHARS.toCharArray()) { for (char ch : FORMAT_CHARS.toCharArray()) {
if (pattern.indexOf(ch) != -1){ // found the character if (pattern.indexOf(ch) != -1) { // found the character
switch(ch) { switch (ch) {
case 'S': case 'S':
return indexOf(Calendar.MILLISECOND); return indexOf(Calendar.MILLISECOND);
case 's': case 's':
@ -111,7 +104,7 @@ public class FTPTimestampParserImpl implements
*/ */
private static int indexOf(int calendarUnit) { private static int indexOf(int calendarUnit) {
int i; int i;
for(i = 0; i <CALENDAR_UNITS.length; i++) { for (i = 0; i < CALENDAR_UNITS.length; i++) {
if (calendarUnit == CALENDAR_UNITS[i]) { if (calendarUnit == CALENDAR_UNITS[i]) {
return i; return i;
} }
@ -128,12 +121,12 @@ public class FTPTimestampParserImpl implements
if (index <= 0) { // e.g. MILLISECONDS if (index <= 0) { // e.g. MILLISECONDS
return; return;
} }
final int field = CALENDAR_UNITS[index-1]; final int field = CALENDAR_UNITS[index - 1];
// Just in case the analysis is wrong, stop clearing if // Just in case the analysis is wrong, stop clearing if
// field value is not the default. // field value is not the default.
final int value = working.get(field); final int value = working.get(field);
if (value != 0) { // don't reset if it has a value if (value != 0) { // don't reset if it has a value
// new Throwable("Unexpected value "+value).printStackTrace(); // DEBUG // new Throwable("Unexpected value "+value).printStackTrace(); // DEBUG
} else { } else {
working.clear(field); // reset just the required field working.clear(field); // reset just the required field
} }
@ -159,13 +152,11 @@ public class FTPTimestampParserImpl implements
* *
* This method assumes that the server time is the same as the local time. * This method assumes that the server time is the same as the local time.
* *
* @see FTPTimestampParserImpl#parseTimestamp(String, Calendar)
*
* @param timestampStr The timestamp to be parsed * @param timestampStr The timestamp to be parsed
* @return a Calendar with the parsed timestamp * @return a Calendar with the parsed timestamp
* @see FTPTimestampParserImpl#parseTimestamp(String, Calendar)
*/ */
@Override @Override public Calendar parseTimestamp(String timestampStr) throws ParseException {
public Calendar parseTimestamp(String timestampStr) throws ParseException {
Calendar now = Calendar.getInstance(); Calendar now = Calendar.getInstance();
return parseTimestamp(timestampStr, now); return parseTimestamp(timestampStr, now);
} }
@ -179,11 +170,11 @@ public class FTPTimestampParserImpl implements
* This method allows a {@link Calendar} instance to be passed in which represents the * This method allows a {@link Calendar} instance to be passed in which represents the
* current (system) time. * current (system) time.
* *
* @see FTPTimestampParser#parseTimestamp(String)
* @param timestampStr The timestamp to be parsed * @param timestampStr The timestamp to be parsed
* @param serverTime The current time for the server * @param serverTime The current time for the server
* @return the calendar * @return the calendar
* @throws ParseException if timestamp cannot be parsed * @throws ParseException if timestamp cannot be parsed
* @see FTPTimestampParser#parseTimestamp(String)
* @since 1.5 * @since 1.5
*/ */
public Calendar parseTimestamp(String timestampStr, Calendar serverTime) throws ParseException { public Calendar parseTimestamp(String timestampStr, Calendar serverTime) throws ParseException {
@ -240,10 +231,10 @@ public class FTPTimestampParserImpl implements
if (parsed != null && pp.getIndex() == timestampStr.length()) { if (parsed != null && pp.getIndex() == timestampStr.length()) {
working.setTime(parsed); working.setTime(parsed);
} else { } else {
throw new ParseException( throw new ParseException("Timestamp '"
"Timestamp '"+timestampStr+"' could not be parsed using a server time of " + timestampStr
+serverTime.getTime().toString(), + "' could not be parsed using a server time of "
pp.getErrorIndex()); + serverTime.getTime().toString(), pp.getErrorIndex());
} }
setPrecision(defaultDateSmallestUnitIndex, working); setPrecision(defaultDateSmallestUnitIndex, working);
return working; return working;
@ -255,12 +246,14 @@ public class FTPTimestampParserImpl implements
public SimpleDateFormat getDefaultDateFormat() { public SimpleDateFormat getDefaultDateFormat() {
return defaultDateFormat; return defaultDateFormat;
} }
/** /**
* @return Returns the defaultDateFormat pattern string. * @return Returns the defaultDateFormat pattern string.
*/ */
public String getDefaultDateFormatString() { public String getDefaultDateFormatString() {
return defaultDateFormat.toPattern(); return defaultDateFormat.toPattern();
} }
/** /**
* @param format The defaultDateFormat to be set. * @param format The defaultDateFormat to be set.
* @param dfs the symbols to use (may be null) * @param dfs the symbols to use (may be null)
@ -278,18 +271,21 @@ public class FTPTimestampParserImpl implements
} }
this.defaultDateSmallestUnitIndex = getEntry(this.defaultDateFormat); this.defaultDateSmallestUnitIndex = getEntry(this.defaultDateFormat);
} }
/** /**
* @return Returns the recentDateFormat. * @return Returns the recentDateFormat.
*/ */
public SimpleDateFormat getRecentDateFormat() { public SimpleDateFormat getRecentDateFormat() {
return recentDateFormat; return recentDateFormat;
} }
/** /**
* @return Returns the recentDateFormat. * @return Returns the recentDateFormat.
*/ */
public String getRecentDateFormatString() { public String getRecentDateFormatString() {
return recentDateFormat.toPattern(); return recentDateFormat.toPattern();
} }
/** /**
* @param format The recentDateFormat to set. * @param format The recentDateFormat to set.
* @param dfs the symbols to use (may be null) * @param dfs the symbols to use (may be null)
@ -316,16 +312,17 @@ public class FTPTimestampParserImpl implements
return defaultDateFormat.getDateFormatSymbols().getShortMonths(); return defaultDateFormat.getDateFormatSymbols().getShortMonths();
} }
/** /**
* @return Returns the serverTimeZone used by this parser. * @return Returns the serverTimeZone used by this parser.
*/ */
public TimeZone getServerTimeZone() { public TimeZone getServerTimeZone() {
return this.defaultDateFormat.getTimeZone(); return this.defaultDateFormat.getTimeZone();
} }
/** /**
* sets a TimeZone represented by the supplied ID string into all * sets a TimeZone represented by the supplied ID string into all
* of the parsers used by this server. * of the parsers used by this server.
*
* @param serverTimeZone Time Id java.util.TimeZone id used by * @param serverTimeZone Time Id java.util.TimeZone id used by
* the ftp server. If null the client's local time zone is assumed. * the ftp server. If null the client's local time zone is assumed.
*/ */
@ -358,13 +355,13 @@ public class FTPTimestampParserImpl implements
* to parse timestamps.</li> * to parse timestamps.</li>
* <li>otherwise use default English month names</li> * <li>otherwise use default English month names</li>
* </ul><p> * </ul><p>
* Finally if a {@link org.apache.commons.net.ftp.FTPClientConfig#setServerTimeZoneId(String) serverTimeZoneId} * Finally if a {@link org.apache.commons.net.ftp.FTPClientConfig#setServerTimeZoneId(String)
* serverTimeZoneId}
* has been supplied via the config, set that into all date formats that have * has been supplied via the config, set that into all date formats that have
* been configured. * been configured.
* </p> * </p>
*/ */
@Override @Override public void configure(FTPClientConfig config) {
public void configure(FTPClientConfig config) {
DateFormatSymbols dfs = null; DateFormatSymbols dfs = null;
String languageCode = config.getServerLanguageCode(); String languageCode = config.getServerLanguageCode();
@ -377,7 +374,6 @@ public class FTPTimestampParserImpl implements
dfs = FTPClientConfig.lookupDateFormatSymbols("en"); dfs = FTPClientConfig.lookupDateFormatSymbols("en");
} }
String recentFormatString = config.getRecentDateFormatStr(); String recentFormatString = config.getRecentDateFormatStr();
setRecentDateFormat(recentFormatString, dfs); setRecentDateFormat(recentFormatString, dfs);
@ -391,12 +387,14 @@ public class FTPTimestampParserImpl implements
this.lenientFutureDates = config.isLenientFutureDates(); this.lenientFutureDates = config.isLenientFutureDates();
} }
/** /**
* @return Returns the lenientFutureDates. * @return Returns the lenientFutureDates.
*/ */
boolean isLenientFutureDates() { boolean isLenientFutureDates() {
return lenientFutureDates; return lenientFutureDates;
} }
/** /**
* @param lenientFutureDates The lenientFutureDates to set. * @param lenientFutureDates The lenientFutureDates to set.
*/ */

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp.parser; package org.apache.commons.net.ftp.parser;
import java.text.ParsePosition; import java.text.ParsePosition;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
@ -54,12 +55,12 @@ import org.apache.commons.net.ftp.FTPFileEntryParserImpl;
* *
* @since 3.0 * @since 3.0
*/ */
public class MLSxEntryParser extends FTPFileEntryParserImpl public class MLSxEntryParser extends FTPFileEntryParserImpl {
{
// This class is immutable, so a single instance can be shared. // This class is immutable, so a single instance can be shared.
private static final MLSxEntryParser PARSER = new MLSxEntryParser(); private static final MLSxEntryParser PARSER = new MLSxEntryParser();
private static final HashMap<String, Integer> TYPE_TO_INT = new HashMap<String, Integer>(); private static final HashMap<String, Integer> TYPE_TO_INT = new HashMap<String, Integer>();
static { static {
TYPE_TO_INT.put("file", Integer.valueOf(FTPFile.FILE_TYPE)); 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("cdir", Integer.valueOf(FTPFile.DIRECTORY_TYPE)); // listed directory
@ -68,33 +69,29 @@ public class MLSxEntryParser extends FTPFileEntryParserImpl
} }
private static int UNIX_GROUPS[] = { // Groups in order of mode digits private static int UNIX_GROUPS[] = { // Groups in order of mode digits
FTPFile.USER_ACCESS, FTPFile.USER_ACCESS, FTPFile.GROUP_ACCESS, FTPFile.WORLD_ACCESS,
FTPFile.GROUP_ACCESS,
FTPFile.WORLD_ACCESS,
}; };
private static int UNIX_PERMS[][] = { // perm bits, broken down by octal int value private static int UNIX_PERMS[][] = { // perm bits, broken down by octal int value
/* 0 */ {}, /* 0 */ {},
/* 1 */ {FTPFile.EXECUTE_PERMISSION}, /* 1 */ { FTPFile.EXECUTE_PERMISSION },
/* 2 */ {FTPFile.WRITE_PERMISSION}, /* 2 */ { FTPFile.WRITE_PERMISSION },
/* 3 */ {FTPFile.EXECUTE_PERMISSION, FTPFile.WRITE_PERMISSION}, /* 3 */ { FTPFile.EXECUTE_PERMISSION, FTPFile.WRITE_PERMISSION },
/* 4 */ {FTPFile.READ_PERMISSION}, /* 4 */ { FTPFile.READ_PERMISSION },
/* 5 */ {FTPFile.READ_PERMISSION, FTPFile.EXECUTE_PERMISSION}, /* 5 */ { FTPFile.READ_PERMISSION, FTPFile.EXECUTE_PERMISSION },
/* 6 */ {FTPFile.READ_PERMISSION, FTPFile.WRITE_PERMISSION}, /* 6 */ { FTPFile.READ_PERMISSION, FTPFile.WRITE_PERMISSION },
/* 7 */ {FTPFile.READ_PERMISSION, FTPFile.WRITE_PERMISSION, FTPFile.EXECUTE_PERMISSION}, /* 7 */ { FTPFile.READ_PERMISSION, FTPFile.WRITE_PERMISSION, FTPFile.EXECUTE_PERMISSION },
}; };
/** /**
* Create the parser for MSLT and MSLD listing entries * Create the parser for MSLT and MSLD listing entries
* This class is immutable, so one can use {@link #getInstance()} instead. * This class is immutable, so one can use {@link #getInstance()} instead.
*/ */
public MLSxEntryParser() public MLSxEntryParser() {
{
super(); super();
} }
@Override @Override public FTPFile parseFTPEntry(String entry) {
public FTPFile parseFTPEntry(String entry) {
if (entry.startsWith(" ")) {// leading space means no facts are present if (entry.startsWith(" ")) {// leading space means no facts are present
if (entry.length() > 1) { // is there a path name? if (entry.length() > 1) { // is there a path name?
FTPFile file = new FTPFile(); FTPFile file = new FTPFile();
@ -104,9 +101,8 @@ public class MLSxEntryParser extends FTPFileEntryParserImpl
} else { } else {
return null; // Invalid - no pathname return null; // Invalid - no pathname
} }
} }
String parts[] = entry.split(" ",2); // Path may contain space String parts[] = entry.split(" ", 2); // Path may contain space
if (parts.length != 2 || parts[1].length() == 0) { if (parts.length != 2 || parts[1].length() == 0) {
return null; // no space found or no file name return null; // no space found or no file name
} }
@ -119,11 +115,11 @@ public class MLSxEntryParser extends FTPFileEntryParserImpl
file.setName(parts[1]); file.setName(parts[1]);
String[] facts = factList.split(";"); String[] facts = factList.split(";");
boolean hasUnixMode = parts[0].toLowerCase(Locale.ENGLISH).contains("unix.mode="); boolean hasUnixMode = parts[0].toLowerCase(Locale.ENGLISH).contains("unix.mode=");
for(String fact : facts) { for (String fact : facts) {
String []factparts = fact.split("=", -1); // Don't drop empty values String[] factparts = fact.split("=", -1); // Don't drop empty values
// Sample missing permission // Sample missing permission
// drwx------ 2 mirror mirror 4096 Mar 13 2010 subversion // 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 // modify=20100313224553;perm=;type=dir;unique=811U282598;UNIX.group=500;UNIX.mode=0700;UNIX.owner=500; subversion
if (factparts.length != 2) { if (factparts.length != 2) {
return null; // invalid - there was no "=" sign return null; // invalid - there was no "=" sign
} }
@ -135,37 +131,33 @@ public class MLSxEntryParser extends FTPFileEntryParserImpl
String valueLowerCase = factvalue.toLowerCase(Locale.ENGLISH); String valueLowerCase = factvalue.toLowerCase(Locale.ENGLISH);
if ("size".equals(factname)) { if ("size".equals(factname)) {
file.setSize(Long.parseLong(factvalue)); file.setSize(Long.parseLong(factvalue));
} } else if ("sizd".equals(factname)) { // Directory size
else if ("sizd".equals(factname)) { // Directory size
file.setSize(Long.parseLong(factvalue)); file.setSize(Long.parseLong(factvalue));
} } else if ("modify".equals(factname)) {
else if ("modify".equals(factname)) {
final Calendar parsed = parseGMTdateTime(factvalue); final Calendar parsed = parseGMTdateTime(factvalue);
if (parsed == null) { if (parsed == null) {
return null; return null;
} }
file.setTimestamp(parsed); file.setTimestamp(parsed);
} } else if ("type".equals(factname)) {
else if ("type".equals(factname)) {
Integer intType = TYPE_TO_INT.get(valueLowerCase); Integer intType = TYPE_TO_INT.get(valueLowerCase);
if (intType == null) { if (intType == null) {
file.setType(FTPFile.UNKNOWN_TYPE); file.setType(FTPFile.UNKNOWN_TYPE);
} else { } else {
file.setType(intType.intValue()); file.setType(intType.intValue());
} }
} } else if (factname.startsWith("unix.")) {
else if (factname.startsWith("unix.")) {
String unixfact = factname.substring("unix.".length()).toLowerCase(Locale.ENGLISH); String unixfact = factname.substring("unix.".length()).toLowerCase(Locale.ENGLISH);
if ("group".equals(unixfact)){ if ("group".equals(unixfact)) {
file.setGroup(factvalue); file.setGroup(factvalue);
} else if ("owner".equals(unixfact)){ } else if ("owner".equals(unixfact)) {
file.setUser(factvalue); file.setUser(factvalue);
} else if ("mode".equals(unixfact)){ // e.g. 0[1]755 } else if ("mode".equals(unixfact)) { // e.g. 0[1]755
int off = factvalue.length()-3; // only parse last 3 digits int off = factvalue.length() - 3; // only parse last 3 digits
for(int i=0; i < 3; i++){ for (int i = 0; i < 3; i++) {
int ch = factvalue.charAt(off+i)-'0'; int ch = factvalue.charAt(off + i) - '0';
if (ch >= 0 && ch <= 7) { // Check it's valid octal if (ch >= 0 && ch <= 7) { // Check it's valid octal
for(int p : UNIX_PERMS[ch]) { for (int p : UNIX_PERMS[ch]) {
file.setPermission(UNIX_GROUPS[i], p, true); file.setPermission(UNIX_GROUPS[i], p, true);
} }
} else { } else {
@ -191,7 +183,7 @@ public class MLSxEntryParser extends FTPFileEntryParserImpl
public static Calendar parseGMTdateTime(String timestamp) { public static Calendar parseGMTdateTime(String timestamp) {
final SimpleDateFormat sdf; final SimpleDateFormat sdf;
final boolean hasMillis; final boolean hasMillis;
if (timestamp.contains(".")){ if (timestamp.contains(".")) {
sdf = new SimpleDateFormat("yyyyMMddHHmmss.SSS"); sdf = new SimpleDateFormat("yyyyMMddHHmmss.SSS");
hasMillis = true; hasMillis = true;
} else { } else {
@ -219,7 +211,7 @@ public class MLSxEntryParser extends FTPFileEntryParserImpl
// pvals = "a" / "c" / "d" / "e" / "f" / // pvals = "a" / "c" / "d" / "e" / "f" /
// "l" / "m" / "p" / "r" / "w" // "l" / "m" / "p" / "r" / "w"
private void doUnixPerms(FTPFile file, String valueLowerCase) { private void doUnixPerms(FTPFile file, String valueLowerCase) {
for(char c : valueLowerCase.toCharArray()) { for (char c : valueLowerCase.toCharArray()) {
// TODO these are mostly just guesses at present // TODO these are mostly just guesses at present
switch (c) { switch (c) {
case 'a': // (file) may APPEnd case 'a': // (file) may APPEnd

@ -99,8 +99,7 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* 1 2 3 4 * 1 2 3 4
* </pre> * </pre>
*/ */
static final String JES_LEVEL_1_LIST_REGEX = static final String JES_LEVEL_1_LIST_REGEX = "(\\S+)\\s+" + // job name ignored
"(\\S+)\\s+" + // job name ignored
"(\\S+)\\s+" + // job number "(\\S+)\\s+" + // job number
"(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE) "(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE)
"(\\S+)\\s+" + // number of spool files "(\\S+)\\s+" + // number of spool files
@ -142,8 +141,7 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* </pre> * </pre>
*/ */
static final String JES_LEVEL_2_LIST_REGEX = static final String JES_LEVEL_2_LIST_REGEX = "(\\S+)\\s+" + // job name ignored
"(\\S+)\\s+" + // job name ignored
"(\\S+)\\s+" + // job number "(\\S+)\\s+" + // job number
"(\\S+)\\s+" + // owner ignored "(\\S+)\\s+" + // owner ignored
"(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE) ignored "(\\S+)\\s+" + // job status (OUTPUT,INPUT,ACTIVE) ignored
@ -240,7 +238,6 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
/** /**
* The sole constructor for a MVSFTPEntryParser object. * The sole constructor for a MVSFTPEntryParser object.
*
*/ */
public MVSFTPEntryParser() { public MVSFTPEntryParser() {
super(""); // note the regex is set in preParse. super(""); // note the regex is set in preParse.
@ -254,12 +251,10 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* <code> null </code> is returned. Otherwise a <code> FTPFile </code> * <code> null </code> is returned. Otherwise a <code> FTPFile </code>
* instance representing the file is returned. * instance representing the file is returned.
* *
* @param entry * @param entry A line of text from the file listing
* A line of text from the file listing
* @return An FTPFile instance corresponding to the supplied entry * @return An FTPFile instance corresponding to the supplied entry
*/ */
@Override @Override public FTPFile parseFTPEntry(String entry) {
public FTPFile parseFTPEntry(String entry) {
boolean isParsed = false; boolean isParsed = false;
FTPFile f = new FTPFile(); FTPFile f = new FTPFile();
@ -305,8 +300,7 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* a tape archive. These entries is currently not supported by this parser. * a tape archive. These entries is currently not supported by this parser.
* A null value is returned. * A null value is returned.
* *
* @param file * @param file will be updated with Name, Type, Timestamp if parsed.
* will be updated with Name, Type, Timestamp if parsed.
* @param entry zosDirectoryEntry * @param entry zosDirectoryEntry
* @return true: entry was parsed, false: entry was not parsed. * @return true: entry was parsed, false: entry was not parsed.
*/ */
@ -320,12 +314,10 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
// DSORG // DSORG
if ("PS".equals(dsorg)) { if ("PS".equals(dsorg)) {
file.setType(FTPFile.FILE_TYPE); file.setType(FTPFile.FILE_TYPE);
} } else if ("PO".equals(dsorg) || "PO-E".equals(dsorg)) {
else if ("PO".equals(dsorg) || "PO-E".equals(dsorg)) {
// regex already ruled out anything other than PO or PO-E // regex already ruled out anything other than PO or PO-E
file.setType(FTPFile.DIRECTORY_TYPE); file.setType(FTPFile.DIRECTORY_TYPE);
} } else {
else {
return false; return false;
} }
@ -356,8 +348,7 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* [9] Id: User id for last update * [9] Id: User id for last update
* </pre> * </pre>
* *
* @param file * @param file will be updated with Name, Type and Timestamp if parsed.
* will be updated with Name, Type and Timestamp if parsed.
* @param entry zosDirectoryEntry * @param entry zosDirectoryEntry
* @return true: entry was parsed, false: entry was not parsed. * @return true: entry was parsed, false: entry was not parsed.
*/ */
@ -387,8 +378,6 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* safe context, for example from a memberlist, where the regex for some * safe context, for example from a memberlist, where the regex for some
* reason fails. Then just assign the name field of FTPFile. * reason fails. Then just assign the name field of FTPFile.
* *
* @param file
* @param entry
* @return true if the entry string is non-null and non-empty * @return true if the entry string is non-null and non-empty
*/ */
private boolean parseSimpleEntry(FTPFile file, String entry) { private boolean parseSimpleEntry(FTPFile file, String entry) {
@ -405,8 +394,6 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
/** /**
* Parse the entry as a standard unix file. Using the UnixFTPEntryParser. * Parse the entry as a standard unix file. Using the UnixFTPEntryParser.
* *
* @param file
* @param entry
* @return true: entry is parsed, false: entry could not be parsed. * @return true: entry is parsed, false: entry could not be parsed.
*/ */
private boolean parseUnixList(FTPFile file, String entry) { private boolean parseUnixList(FTPFile file, String entry) {
@ -431,10 +418,9 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* [3] Job status (INPUT,ACTIVE,OUTPUT) * [3] Job status (INPUT,ACTIVE,OUTPUT)
* [4] Number of sysout files * [4] Number of sysout files
* [5] The string "Spool Files" * [5] The string "Spool Files"
*</pre> * </pre>
* *
* @param file * @param file will be updated with Name, Type and Timestamp if parsed.
* will be updated with Name, Type and Timestamp if parsed.
* @param entry zosDirectoryEntry * @param entry zosDirectoryEntry
* @return true: entry was parsed, false: entry was not parsed. * @return true: entry was parsed, false: entry was not parsed.
*/ */
@ -471,8 +457,7 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* [6] The rest * [6] The rest
* </pre> * </pre>
* *
* @param file * @param file will be updated with Name, Type and Timestamp if parsed.
* will be updated with Name, Type and Timestamp if parsed.
* @param entry zosDirectoryEntry * @param entry zosDirectoryEntry
* @return true: entry was parsed, false: entry was not parsed. * @return true: entry was parsed, false: entry was not parsed.
*/ */
@ -497,10 +482,10 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* z/OS-MVS File lists * z/OS-MVS File lists
* z/OS-MVS Member lists * z/OS-MVS Member lists
* unix file lists * unix file lists
*
* @since 2.0 * @since 2.0
*/ */
@Override @Override public List<String> preParse(List<String> orig) {
public List<String> preParse(List<String> orig) {
// simply remove the header line. Composite logic will take care of the // simply remove the header line. Composite logic will take care of the
// two different types of // two different types of
// list in short order. // list in short order.
@ -536,6 +521,7 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
/** /**
* Explicitly set the type of listing being processed. * Explicitly set the type of listing being processed.
*
* @param type The listing type. * @param type The listing type.
*/ */
void setType(int type) { void setType(int type) {
@ -545,10 +531,7 @@ public class MVSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
/* /*
* @return * @return
*/ */
@Override @Override protected FTPClientConfig getDefaultConfiguration() {
protected FTPClientConfig getDefaultConfiguration() { return new FTPClientConfig(FTPClientConfig.SYST_MVS, DEFAULT_DATE_FORMAT, null);
return new FTPClientConfig(FTPClientConfig.SYST_MVS,
DEFAULT_DATE_FORMAT, null);
} }
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp.parser; package org.apache.commons.net.ftp.parser;
import java.text.ParseException; import java.text.ParseException;
import org.apache.commons.net.ftp.FTPClientConfig; import org.apache.commons.net.ftp.FTPClientConfig;
@ -28,14 +29,11 @@ import org.apache.commons.net.ftp.FTPFile;
* @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
* @since 3.1 * @since 3.1
*/ */
public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
{
static final String DEFAULT_DATE_FORMAT static final String DEFAULT_DATE_FORMAT = "MMM d yyyy"; //Nov 9 2001
= "MMM d yyyy"; //Nov 9 2001
static final String DEFAULT_RECENT_DATE_FORMAT static final String DEFAULT_RECENT_DATE_FORMAT = "MMM d HH:mm"; //Nov 9 20:06
= "MMM d HH:mm"; //Nov 9 20:06
/** /**
* this is the regular expression used by this parser. * this is the regular expression used by this parser.
@ -57,15 +55,18 @@ public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* state) * state)
* e z/OS external link bit * e z/OS external link bit
*/ */
private static final String REGEX = private static final String REGEX = "([bcdelfmpSs-])"
"([bcdelfmpSs-])" // type (1) // type (1)
+ "(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?\\s+" // permission + "(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?\\s+"
// permission
+ "(" + "("
+ "(folder\\s+)" + "(folder\\s+)"
+ "|" + "|"
+ "((\\d+)\\s+(\\d+)\\s+)" // resource size & data size + "((\\d+)\\s+(\\d+)\\s+)"
// resource size & data size
+ ")" + ")"
+ "(\\d+)\\s+" // size + "(\\d+)\\s+"
// size
/* /*
* numeric or standard format date: * numeric or standard format date:
* yyyy-mm-dd (expecting hh:mm to follow) * yyyy-mm-dd (expecting hh:mm to follow)
@ -83,17 +84,15 @@ public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
+ "(\\S*)(\\s*.*)"; // the rest + "(\\S*)(\\s*.*)"; // the rest
/** /**
* The default constructor for a UnixFTPEntryParser object. * The default constructor for a UnixFTPEntryParser object.
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
*/ */
public MacOsPeterFTPEntryParser() public MacOsPeterFTPEntryParser() {
{
this(null); this(null);
} }
@ -103,14 +102,13 @@ public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* *
* @param config The {@link FTPClientConfig configuration} object used to * @param config The {@link FTPClientConfig configuration} object used to
* configure this parser. * configure this parser.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
* @since 1.4 * @since 1.4
*/ */
public MacOsPeterFTPEntryParser(FTPClientConfig config) public MacOsPeterFTPEntryParser(FTPClientConfig config) {
{
super(REGEX); super(REGEX);
configure(config); configure(config);
} }
@ -125,15 +123,13 @@ public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* @param entry A line of text from the file listing * @param entry A line of text from the file listing
* @return An FTPFile instance corresponding to the supplied entry * @return An FTPFile instance corresponding to the supplied entry
*/ */
@Override @Override public FTPFile parseFTPEntry(String entry) {
public FTPFile parseFTPEntry(String entry) {
FTPFile file = new FTPFile(); FTPFile file = new FTPFile();
file.setRawListing(entry); file.setRawListing(entry);
int type; int type;
boolean isDevice = false; boolean isDevice = false;
if (matches(entry)) if (matches(entry)) {
{
String typeStr = group(1); String typeStr = group(1);
String hardLinkCount = "0"; String hardLinkCount = "0";
String usr = null; String usr = null;
@ -143,12 +139,9 @@ public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
String name = group(23); String name = group(23);
String endtoken = group(24); String endtoken = group(24);
try try {
{
file.setTimestamp(super.parseTimestamp(datestr)); file.setTimestamp(super.parseTimestamp(datestr));
} } catch (ParseException e) {
catch (ParseException e)
{
// intentionally do nothing // intentionally do nothing
} }
@ -156,8 +149,7 @@ public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
// 'translucent' filesystems, of which a 'union' filesystem is one. // 'translucent' filesystems, of which a 'union' filesystem is one.
// bcdelfmpSs- // bcdelfmpSs-
switch (typeStr.charAt(0)) switch (typeStr.charAt(0)) {
{
case 'd': case 'd':
type = FTPFile.DIRECTORY_TYPE; type = FTPFile.DIRECTORY_TYPE;
break; break;
@ -183,33 +175,23 @@ public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
file.setType(type); file.setType(type);
int g = 4; int g = 4;
for (int access = 0; access < 3; access++, g += 4) for (int access = 0; access < 3; access++, g += 4) {
{
// Use != '-' to avoid having to check for suid and sticky bits // Use != '-' to avoid having to check for suid and sticky bits
file.setPermission(access, FTPFile.READ_PERMISSION, file.setPermission(access, FTPFile.READ_PERMISSION, (!group(g).equals("-")));
(!group(g).equals("-"))); file.setPermission(access, FTPFile.WRITE_PERMISSION, (!group(g + 1).equals("-")));
file.setPermission(access, FTPFile.WRITE_PERMISSION,
(!group(g + 1).equals("-")));
String execPerm = group(g + 2); String execPerm = group(g + 2);
if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) {
{
file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true); file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true);
} } else {
else
{
file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false); file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false);
} }
} }
if (!isDevice) if (!isDevice) {
{ try {
try
{
file.setHardLinkCount(Integer.parseInt(hardLinkCount)); file.setHardLinkCount(Integer.parseInt(hardLinkCount));
} } catch (NumberFormatException e) {
catch (NumberFormatException e)
{
// intentionally do nothing // intentionally do nothing
} }
} }
@ -217,42 +199,29 @@ public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
file.setUser(usr); file.setUser(usr);
file.setGroup(grp); file.setGroup(grp);
try try {
{
file.setSize(Long.parseLong(filesize)); file.setSize(Long.parseLong(filesize));
} } catch (NumberFormatException e) {
catch (NumberFormatException e)
{
// intentionally do nothing // intentionally do nothing
} }
if (null == endtoken) if (null == endtoken) {
{
file.setName(name); file.setName(name);
} } else {
else
{
// oddball cases like symbolic links, file names // oddball cases like symbolic links, file names
// with spaces in them. // with spaces in them.
name += endtoken; name += endtoken;
if (type == FTPFile.SYMBOLIC_LINK_TYPE) if (type == FTPFile.SYMBOLIC_LINK_TYPE) {
{
int end = name.indexOf(" -> "); int end = name.indexOf(" -> ");
// Give up if no link indicator is present // Give up if no link indicator is present
if (end == -1) if (end == -1) {
{
file.setName(name); file.setName(name);
} } else {
else
{
file.setName(name.substring(0, end)); file.setName(name.substring(0, end));
file.setLink(name.substring(end + 4)); file.setLink(name.substring(end + 4));
} }
} else {
}
else
{
file.setName(name); file.setName(name);
} }
} }
@ -265,14 +234,11 @@ public class MacOsPeterFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* Defines a default configuration to be used when this class is * Defines a default configuration to be used when this class is
* instantiated without a {@link FTPClientConfig FTPClientConfig} * instantiated without a {@link FTPClientConfig FTPClientConfig}
* parameter being specified. * parameter being specified.
*
* @return the default configuration for this parser. * @return the default configuration for this parser.
*/ */
@Override @Override protected FTPClientConfig getDefaultConfiguration() {
protected FTPClientConfig getDefaultConfiguration() { return new FTPClientConfig(FTPClientConfig.SYST_UNIX, DEFAULT_DATE_FORMAT,
return new FTPClientConfig(
FTPClientConfig.SYST_UNIX,
DEFAULT_DATE_FORMAT,
DEFAULT_RECENT_DATE_FORMAT); DEFAULT_RECENT_DATE_FORMAT);
} }
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp.parser; package org.apache.commons.net.ftp.parser;
import java.text.ParseException; import java.text.ParseException;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -29,14 +30,11 @@ import org.apache.commons.net.ftp.FTPFile;
* @version $Id: NTFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ * @version $Id: NTFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $
* @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
*/ */
public class NTFTPEntryParser extends ConfigurableFTPFileEntryParserImpl public class NTFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
{
private static final String DEFAULT_DATE_FORMAT private static final String DEFAULT_DATE_FORMAT = "MM-dd-yy hh:mma"; //11-09-01 12:30PM
= "MM-dd-yy hh:mma"; //11-09-01 12:30PM
private static final String DEFAULT_DATE_FORMAT2 private static final String DEFAULT_DATE_FORMAT2 = "MM-dd-yy kk:mm"; //11-09-01 18:30
= "MM-dd-yy kk:mm"; //11-09-01 18:30
private final FTPTimestampParser timestampParser; private final FTPTimestampParser timestampParser;
@ -51,13 +49,12 @@ public class NTFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
/** /**
* The sole constructor for an NTFTPEntryParser object. * The sole constructor for an NTFTPEntryParser object.
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
*/ */
public NTFTPEntryParser() public NTFTPEntryParser() {
{
this(null); this(null);
} }
@ -67,23 +64,20 @@ public class NTFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* *
* @param config The {@link FTPClientConfig configuration} object used to * @param config The {@link FTPClientConfig configuration} object used to
* configure this parser. * configure this parser.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
* @since 1.4 * @since 1.4
*/ */
public NTFTPEntryParser(FTPClientConfig config) public NTFTPEntryParser(FTPClientConfig config) {
{
super(REGEX, Pattern.DOTALL); super(REGEX, Pattern.DOTALL);
configure(config); configure(config);
FTPClientConfig config2 = new FTPClientConfig( FTPClientConfig config2 =
FTPClientConfig.SYST_NT, new FTPClientConfig(FTPClientConfig.SYST_NT, DEFAULT_DATE_FORMAT2, null);
DEFAULT_DATE_FORMAT2,
null);
config2.setDefaultDateFormatStr(DEFAULT_DATE_FORMAT2); config2.setDefaultDateFormatStr(DEFAULT_DATE_FORMAT2);
this.timestampParser = new FTPTimestampParserImpl(); this.timestampParser = new FTPTimestampParserImpl();
((Configurable)this.timestampParser).configure(config2); ((Configurable) this.timestampParser).configure(config2);
} }
/** /**
@ -96,52 +90,37 @@ public class NTFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* @param entry A line of text from the file listing * @param entry A line of text from the file listing
* @return An FTPFile instance corresponding to the supplied entry * @return An FTPFile instance corresponding to the supplied entry
*/ */
@Override @Override public FTPFile parseFTPEntry(String entry) {
public FTPFile parseFTPEntry(String entry)
{
FTPFile f = new FTPFile(); FTPFile f = new FTPFile();
f.setRawListing(entry); f.setRawListing(entry);
if (matches(entry)) if (matches(entry)) {
{ String datestr = group(1) + " " + group(2);
String datestr = group(1)+" "+group(2);
String dirString = group(3); String dirString = group(3);
String size = group(4); String size = group(4);
String name = group(5); String name = group(5);
try try {
{
f.setTimestamp(super.parseTimestamp(datestr)); f.setTimestamp(super.parseTimestamp(datestr));
} } catch (ParseException e) {
catch (ParseException e)
{
// parsing fails, try the other date format // parsing fails, try the other date format
try try {
{
f.setTimestamp(timestampParser.parseTimestamp(datestr)); f.setTimestamp(timestampParser.parseTimestamp(datestr));
} } catch (ParseException e2) {
catch (ParseException e2)
{
// intentionally do nothing // intentionally do nothing
} }
} }
if (null == name || name.equals(".") || name.equals("..")) if (null == name || name.equals(".") || name.equals("..")) {
{
return (null); return (null);
} }
f.setName(name); f.setName(name);
if ("<DIR>".equals(dirString)) {
if ("<DIR>".equals(dirString))
{
f.setType(FTPFile.DIRECTORY_TYPE); f.setType(FTPFile.DIRECTORY_TYPE);
f.setSize(0); f.setSize(0);
} } else {
else
{
f.setType(FTPFile.FILE_TYPE); f.setType(FTPFile.FILE_TYPE);
if (null != size) if (null != size) {
{
f.setSize(Long.parseLong(size)); f.setSize(Long.parseLong(size));
} }
} }
@ -154,14 +133,10 @@ public class NTFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* Defines a default configuration to be used when this class is * Defines a default configuration to be used when this class is
* instantiated without a {@link FTPClientConfig FTPClientConfig} * instantiated without a {@link FTPClientConfig FTPClientConfig}
* parameter being specified. * parameter being specified.
*
* @return the default configuration for this parser. * @return the default configuration for this parser.
*/ */
@Override @Override public FTPClientConfig getDefaultConfiguration() {
public FTPClientConfig getDefaultConfiguration() { return new FTPClientConfig(FTPClientConfig.SYST_NT, DEFAULT_DATE_FORMAT, null);
return new FTPClientConfig(
FTPClientConfig.SYST_NT,
DEFAULT_DATE_FORMAT,
null);
} }
} }

@ -23,14 +23,15 @@ import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile; import org.apache.commons.net.ftp.FTPFile;
/** /**
* Implementation of FTPFileEntryParser and FTPFileListParser for Netware Systems. Note that some of the proprietary * Implementation of FTPFileEntryParser and FTPFileListParser for Netware Systems. Note that some of
* the proprietary
* extensions for Novell-specific operations are not supported. See * extensions for Novell-specific operations are not supported. See
* <a href="http://www.novell.com/documentation/nw65/index.html?page=/documentation/nw65/ftp_enu/data/fbhbgcfa.html"> * <a href="http://www.novell.com/documentation/nw65/index.html?page=/documentation/nw65/ftp_enu/data/fbhbgcfa.html">
* http://www.novell.com/documentation/nw65/index.html?page=/documentation/nw65/ftp_enu/data/fbhbgcfa.html</a> * http://www.novell.com/documentation/nw65/index.html?page=/documentation/nw65/ftp_enu/data/fbhbgcfa.html</a>
* for more details. * for more details.
* *
* @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
* @version $Id: NetwareFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ * @version $Id: NetwareFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $
* @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
* @since 1.5 * @since 1.5
*/ */
public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl { public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
@ -58,8 +59,8 @@ public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
/** /**
* The default constructor for a NetwareFTPEntryParser object. * The default constructor for a NetwareFTPEntryParser object.
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
*/ */
@ -73,8 +74,8 @@ public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* *
* @param config The {@link FTPClientConfig configuration} object used to * @param config The {@link FTPClientConfig configuration} object used to
* configure this parser. * configure this parser.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
* @since 1.4 * @since 1.4
@ -96,11 +97,13 @@ public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* <li><b>S</b> - Supervisor; All rights. * <li><b>S</b> - Supervisor; All rights.
* <li><b>R</b> - Read; Right to open and read or execute. * <li><b>R</b> - Read; Right to open and read or execute.
* <li><b>W</b> - Write; Right to open and modify. * <li><b>W</b> - Write; Right to open and modify.
* <li><b>C</b> - Create; Right to create; when assigned to a file, allows a deleted file to be recovered. * <li><b>C</b> - Create; Right to create; when assigned to a file, allows a deleted file to be
* recovered.
* <li><b>E</b> - Erase; Right to delete. * <li><b>E</b> - Erase; Right to delete.
* <li><b>M</b> - Modify; Right to rename a file and to change attributes. * <li><b>M</b> - Modify; Right to rename a file and to change attributes.
* <li><b>F</b> - File Scan; Right to see directory or file listings. * <li><b>F</b> - File Scan; Right to see directory or file listings.
* <li><b>A</b> - Access Control; Right to modify trustee assignments and the Inherited Rights Mask. * <li><b>A</b> - Access Control; Right to modify trustee assignments and the Inherited Rights
* Mask.
* </ul> * </ul>
* *
* See * See
@ -111,8 +114,7 @@ public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
* @param entry A line of text from the file listing * @param entry A line of text from the file listing
* @return An FTPFile instance corresponding to the supplied entry * @return An FTPFile instance corresponding to the supplied entry
*/ */
@Override @Override public FTPFile parseFTPEntry(String entry) {
public FTPFile parseFTPEntry(String entry) {
FTPFile f = new FTPFile(); FTPFile f = new FTPFile();
if (matches(entry)) { if (matches(entry)) {
@ -148,30 +150,26 @@ public class NetwareFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
// Now set the permissions (or at least a subset thereof - full permissions would probably require // Now set the permissions (or at least a subset thereof - full permissions would probably require
// subclassing FTPFile and adding extra metainformation there) // subclassing FTPFile and adding extra metainformation there)
if (attrib.indexOf("R") != -1) { if (attrib.indexOf("R") != -1) {
f.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, f.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, true);
true);
} }
if (attrib.indexOf("W") != -1) { if (attrib.indexOf("W") != -1) {
f.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, f.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true);
true);
} }
return (f); return (f);
} }
return null; return null;
} }
/** /**
* Defines a default configuration to be used when this class is * Defines a default configuration to be used when this class is
* instantiated without a {@link FTPClientConfig FTPClientConfig} * instantiated without a {@link FTPClientConfig FTPClientConfig}
* parameter being specified. * parameter being specified.
*
* @return the default configuration for this parser. * @return the default configuration for this parser.
*/ */
@Override @Override protected FTPClientConfig getDefaultConfiguration() {
protected FTPClientConfig getDefaultConfiguration() { return new FTPClientConfig(FTPClientConfig.SYST_NETWARE, DEFAULT_DATE_FORMAT,
return new FTPClientConfig(FTPClientConfig.SYST_NETWARE, DEFAULT_RECENT_DATE_FORMAT);
DEFAULT_DATE_FORMAT, DEFAULT_RECENT_DATE_FORMAT);
} }
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp.parser; package org.apache.commons.net.ftp.parser;
import java.text.ParseException; import java.text.ParseException;
import org.apache.commons.net.ftp.FTPClientConfig; import org.apache.commons.net.ftp.FTPClientConfig;
@ -31,13 +32,11 @@ public class OS2FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
{ {
private static final String DEFAULT_DATE_FORMAT private static final String DEFAULT_DATE_FORMAT = "MM-dd-yy HH:mm"; //11-09-01 12:30
= "MM-dd-yy HH:mm"; //11-09-01 12:30
/** /**
* this is the regular expression used by this parser. * this is the regular expression used by this parser.
*/ */
private static final String REGEX = private static final String REGEX = "\\s*([0-9]+)\\s*"
"\\s*([0-9]+)\\s*"
+ "(\\s+|[A-Z]+)\\s*" + "(\\s+|[A-Z]+)\\s*"
+ "(DIR|\\s+)\\s*" + "(DIR|\\s+)\\s*"
+ "(\\S+)\\s+(\\S+)\\s+" /* date stuff */ + "(\\S+)\\s+(\\S+)\\s+" /* date stuff */
@ -46,13 +45,12 @@ public class OS2FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
/** /**
* The default constructor for a OS2FTPEntryParser object. * The default constructor for a OS2FTPEntryParser object.
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
*/ */
public OS2FTPEntryParser() public OS2FTPEntryParser() {
{
this(null); this(null);
} }
@ -62,14 +60,13 @@ public class OS2FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* *
* @param config The {@link FTPClientConfig configuration} object used to * @param config The {@link FTPClientConfig configuration} object used to
* configure this parser. * configure this parser.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
* @since 1.4 * @since 1.4
*/ */
public OS2FTPEntryParser(FTPClientConfig config) public OS2FTPEntryParser(FTPClientConfig config) {
{
super(REGEX); super(REGEX);
configure(config); configure(config);
} }
@ -84,39 +81,28 @@ public class OS2FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* @param entry A line of text from the file listing * @param entry A line of text from the file listing
* @return An FTPFile instance corresponding to the supplied entry * @return An FTPFile instance corresponding to the supplied entry
*/ */
@Override @Override public FTPFile parseFTPEntry(String entry) {
public FTPFile parseFTPEntry(String entry)
{
FTPFile f = new FTPFile(); FTPFile f = new FTPFile();
if (matches(entry)) if (matches(entry)) {
{
String size = group(1); String size = group(1);
String attrib = group(2); String attrib = group(2);
String dirString = group(3); String dirString = group(3);
String datestr = group(4)+" "+group(5); String datestr = group(4) + " " + group(5);
String name = group(6); String name = group(6);
try try {
{
f.setTimestamp(super.parseTimestamp(datestr)); f.setTimestamp(super.parseTimestamp(datestr));
} } catch (ParseException e) {
catch (ParseException e)
{
// intentionally do nothing // intentionally do nothing
} }
//is it a DIR or a file //is it a DIR or a file
if (dirString.trim().equals("DIR") || attrib.trim().equals("DIR")) if (dirString.trim().equals("DIR") || attrib.trim().equals("DIR")) {
{
f.setType(FTPFile.DIRECTORY_TYPE); f.setType(FTPFile.DIRECTORY_TYPE);
} } else {
else
{
f.setType(FTPFile.FILE_TYPE); f.setType(FTPFile.FILE_TYPE);
} }
//set the name //set the name
f.setName(name.trim()); f.setName(name.trim());
@ -126,21 +112,16 @@ public class OS2FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
return (f); return (f);
} }
return null; return null;
} }
/** /**
* Defines a default configuration to be used when this class is * Defines a default configuration to be used when this class is
* instantiated without a {@link FTPClientConfig FTPClientConfig} * instantiated without a {@link FTPClientConfig FTPClientConfig}
* parameter being specified. * parameter being specified.
*
* @return the default configuration for this parser. * @return the default configuration for this parser.
*/ */
@Override @Override protected FTPClientConfig getDefaultConfiguration() {
protected FTPClientConfig getDefaultConfiguration() { return new FTPClientConfig(FTPClientConfig.SYST_OS2, DEFAULT_DATE_FORMAT, null);
return new FTPClientConfig(
FTPClientConfig.SYST_OS2,
DEFAULT_DATE_FORMAT,
null);
} }
} }

@ -165,9 +165,12 @@ import org.apache.commons.net.ftp.FTPFile;
* *
* [echo] Downloading members of a file: * [echo] Downloading members of a file:
* [ftp] getting files * [ftp] getting files
* [ftp] transferring RUN.MBR to C:\workspaces\rdp_080\workspace\ANT - FTP\i5-downloads-file\RUN.MBR * [ftp] transferring RUN.MBR to C:\workspaces\rdp_080\workspace\ANT -
* [ftp] transferring RUNNER.MBR to C:\workspaces\rdp_080\workspace\ANT - FTP\i5-downloads-file\RUNNER.MBR * FTP\i5-downloads-file\RUN.MBR
* [ftp] transferring RUNNERBND.MBR to C:\workspaces\rdp_080\workspace\ANT - FTP\i5-downloads-file\RUNNERBND.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 * [ftp] 3 files retrieved
* *
* *
@ -196,12 +199,18 @@ import org.apache.commons.net.ftp.FTPFile;
* *
* [echo] Downloading members of all files of a library: * [echo] Downloading members of all files of a library:
* [ftp] getting files * [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\RUN.MBR to C:\work\rdp_080\space\ANT -
* [ftp] transferring RPGUNIT1.FILE\RUNRMT.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNIT1.FILE\RUNRMT.MBR * FTP\i5-downloads\RPGUNIT1.FILE\RUN.MBR
* [ftp] transferring RPGUNITT1.FILE\RUNT.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNITT1.FILE\RUNT.MBR * [ftp] transferring RPGUNIT1.FILE\RUNRMT.MBR to C:\work\rdp_080\space\ANT -
* [ftp] transferring RPGUNITY1.FILE\RUN.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNITY1.FILE\RUN.MBR * FTP\i5-downloads\RPGUNIT1.FILE\RUNRMT.MBR
* [ftp] transferring RPGUNITY1.FILE\RUNNER.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNITY1.FILE\RUNNER.MBR * [ftp] transferring RPGUNITT1.FILE\RUNT.MBR to C:\work\rdp_080\space\ANT -
* [ftp] transferring RPGUNITY1.FILE\RUNNERBND.MBR to C:\work\rdp_080\space\ANT - FTP\i5-downloads\RPGUNITY1.FILE\RUNNERBND.MBR * 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 * [ftp] 6 files retrieved
* *
* *
@ -231,31 +240,24 @@ import org.apache.commons.net.ftp.FTPFile;
* *
* </pre> * </pre>
*/ */
public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl 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 DEFAULT_DATE_FORMAT
= "yy/MM/dd HH:mm:ss"; //01/11/09 12:30:24
private static final String REGEX = "(\\S+)\\s+" // user
private static final String REGEX =
"(\\S+)\\s+" // user
+ "(?:(\\d+)\\s+)?" // size, empty for members + "(?:(\\d+)\\s+)?" // size, empty for members
+ "(?:(\\S+)\\s+(\\S+)\\s+)?" // date stuff, empty for members + "(?:(\\S+)\\s+(\\S+)\\s+)?" // date stuff, empty for members
+ "(\\*STMF|\\*DIR|\\*FILE|\\*MEM)\\s+" // *STMF/*DIR/*FILE/*MEM + "(\\*STMF|\\*DIR|\\*FILE|\\*MEM)\\s+" // *STMF/*DIR/*FILE/*MEM
+ "(?:(\\S+)\\s*)?"; // filename, missing, when CWD is a *FILE + "(?:(\\S+)\\s*)?"; // filename, missing, when CWD is a *FILE
/** /**
* The default constructor for a OS400FTPEntryParser object. * The default constructor for a OS400FTPEntryParser object.
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
*/ */
public OS400FTPEntryParser() public OS400FTPEntryParser() {
{
this(null); this(null);
} }
@ -265,69 +267,52 @@ public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* *
* @param config The {@link FTPClientConfig configuration} object used to * @param config The {@link FTPClientConfig configuration} object used to
* configure this parser. * configure this parser.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
* @since 1.4 * @since 1.4
*/ */
public OS400FTPEntryParser(FTPClientConfig config) public OS400FTPEntryParser(FTPClientConfig config) {
{
super(REGEX); super(REGEX);
configure(config); configure(config);
} }
@Override public FTPFile parseFTPEntry(String entry) {
@Override
public FTPFile parseFTPEntry(String entry)
{
FTPFile file = new FTPFile(); FTPFile file = new FTPFile();
file.setRawListing(entry); file.setRawListing(entry);
int type; int type;
if (matches(entry)) if (matches(entry)) {
{
String usr = group(1); String usr = group(1);
String filesize = group(2); String filesize = group(2);
String datestr = ""; String datestr = "";
if (!isNullOrEmpty(group(3)) || !isNullOrEmpty(group(4))) if (!isNullOrEmpty(group(3)) || !isNullOrEmpty(group(4))) {
{ datestr = group(3) + " " + group(4);
datestr = group(3)+" "+group(4);
} }
String typeStr = group(5); String typeStr = group(5);
String name = group(6); String name = group(6);
boolean mustScanForPathSeparator = true; boolean mustScanForPathSeparator = true;
try try {
{
file.setTimestamp(super.parseTimestamp(datestr)); file.setTimestamp(super.parseTimestamp(datestr));
} } catch (ParseException e) {
catch (ParseException e)
{
// intentionally do nothing // intentionally do nothing
} }
if (typeStr.equalsIgnoreCase("*STMF")) {
if (typeStr.equalsIgnoreCase("*STMF"))
{
type = FTPFile.FILE_TYPE; type = FTPFile.FILE_TYPE;
if (isNullOrEmpty(filesize) || isNullOrEmpty(name)) if (isNullOrEmpty(filesize) || isNullOrEmpty(name)) {
{
return null; return null;
} }
} } else if (typeStr.equalsIgnoreCase("*DIR")) {
else if (typeStr.equalsIgnoreCase("*DIR"))
{
type = FTPFile.DIRECTORY_TYPE; type = FTPFile.DIRECTORY_TYPE;
if (isNullOrEmpty(filesize) || isNullOrEmpty(name)) if (isNullOrEmpty(filesize) || isNullOrEmpty(name)) {
{
return null; return null;
} }
} } else if (typeStr.equalsIgnoreCase("*FILE")) {
else if (typeStr.equalsIgnoreCase("*FILE"))
{
// File, defines the structure of the data (columns of a row) // File, defines the structure of the data (columns of a row)
// but the data is stored in one or more members. Typically a // but the data is stored in one or more members. Typically a
// source file contains multiple members whereas it is // source file contains multiple members whereas it is
@ -335,27 +320,20 @@ public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
// file. // file.
// Save files are a special type of files which are used // Save files are a special type of files which are used
// to save objects, e.g. for backups. // to save objects, e.g. for backups.
if (name != null && name.toUpperCase().endsWith(".SAVF")) if (name != null && name.toUpperCase().endsWith(".SAVF")) {
{
mustScanForPathSeparator = false; mustScanForPathSeparator = false;
type = FTPFile.FILE_TYPE; type = FTPFile.FILE_TYPE;
} } else {
else
{
return null; return null;
} }
} } else if (typeStr.equalsIgnoreCase("*MEM")) {
else if (typeStr.equalsIgnoreCase("*MEM"))
{
mustScanForPathSeparator = false; mustScanForPathSeparator = false;
type = FTPFile.FILE_TYPE; type = FTPFile.FILE_TYPE;
if (isNullOrEmpty(name)) if (isNullOrEmpty(name)) {
{
return null; return null;
} }
if (!(isNullOrEmpty(filesize) && isNullOrEmpty(datestr))) if (!(isNullOrEmpty(filesize) && isNullOrEmpty(datestr))) {
{
return null; return null;
} }
@ -365,9 +343,7 @@ public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
// use the separator of the FTP server, which is a forward // use the separator of the FTP server, which is a forward
// slash in case of an AS/400. // slash in case of an AS/400.
name = name.replace('/', File.separatorChar); name = name.replace('/', File.separatorChar);
} } else {
else
{
type = FTPFile.UNKNOWN_TYPE; type = FTPFile.UNKNOWN_TYPE;
} }
@ -375,24 +351,18 @@ public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
file.setUser(usr); file.setUser(usr);
try try {
{
file.setSize(Long.parseLong(filesize)); file.setSize(Long.parseLong(filesize));
} } catch (NumberFormatException e) {
catch (NumberFormatException e)
{
// intentionally do nothing // intentionally do nothing
} }
if (name.endsWith("/")) if (name.endsWith("/")) {
{
name = name.substring(0, name.length() - 1); name = name.substring(0, name.length() - 1);
} }
if (mustScanForPathSeparator) if (mustScanForPathSeparator) {
{
int pos = name.lastIndexOf('/'); int pos = name.lastIndexOf('/');
if (pos > -1) if (pos > -1) {
{
name = name.substring(pos + 1); name = name.substring(pos + 1);
} }
} }
@ -405,7 +375,6 @@ public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
} }
/** /**
*
* @param string String value that is checked for <code>null</code> * @param string String value that is checked for <code>null</code>
* or empty. * or empty.
* @return <code>true</code> for <code>null</code> or empty values, * @return <code>true</code> for <code>null</code> or empty values,
@ -422,14 +391,10 @@ public class OS400FTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* Defines a default configuration to be used when this class is * Defines a default configuration to be used when this class is
* instantiated without a {@link FTPClientConfig FTPClientConfig} * instantiated without a {@link FTPClientConfig FTPClientConfig}
* parameter being specified. * parameter being specified.
*
* @return the default configuration for this parser. * @return the default configuration for this parser.
*/ */
@Override @Override protected FTPClientConfig getDefaultConfiguration() {
protected FTPClientConfig getDefaultConfiguration() { return new FTPClientConfig(FTPClientConfig.SYST_OS400, DEFAULT_DATE_FORMAT, null);
return new FTPClientConfig(
FTPClientConfig.SYST_OS400,
DEFAULT_DATE_FORMAT,
null);
} }
} }

@ -54,9 +54,7 @@ public class ParserInitializationException extends RuntimeException {
* @return the root cause of this exception being thrown * @return the root cause of this exception being thrown
* @deprecated use {@link #getCause()} instead * @deprecated use {@link #getCause()} instead
*/ */
@Deprecated @Deprecated public Throwable getRootCause() {
public Throwable getRootCause() {
return super.getCause(); return super.getCause();
} }
} }

@ -15,7 +15,6 @@
* limitations under the License. * limitations under the License.
*/ */
package org.apache.commons.net.ftp.parser; package org.apache.commons.net.ftp.parser;
import java.util.regex.MatchResult; import java.util.regex.MatchResult;
@ -32,8 +31,7 @@ import org.apache.commons.net.ftp.FTPFileEntryParserImpl;
* *
* This is the base class for all regular expression based FTPFileEntryParser classes * This is the base class for all regular expression based FTPFileEntryParser classes
*/ */
public abstract class RegexFTPFileEntryParserImpl extends public abstract class RegexFTPFileEntryParserImpl extends FTPFileEntryParserImpl {
FTPFileEntryParserImpl {
/** /**
* internal pattern the matcher tries to match, representing a file * internal pattern the matcher tries to match, representing a file
* entry * entry
@ -57,9 +55,8 @@ public abstract class RegexFTPFileEntryParserImpl extends
* *
* @param regex The regular expression with which this object is * @param regex The regular expression with which this object is
* initialized. * initialized.
* * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* @throws IllegalArgumentException * be seen in
* 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 * 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 * been created with a bad regular expression. Since the parser must be
* created before use, this means that any bad parser subclasses created * created before use, this means that any bad parser subclasses created
@ -77,9 +74,8 @@ public abstract class RegexFTPFileEntryParserImpl extends
* @param regex The regular expression with which this object is * @param regex The regular expression with which this object is
* initialized. * initialized.
* @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none. * @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
* @throws IllegalArgumentException * be seen in
* 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 * 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 * been created with a bad regular expression. Since the parser must be
* created before use, this means that any bad parser subclasses created * created before use, this means that any bad parser subclasses created
@ -126,7 +122,6 @@ public abstract class RegexFTPFileEntryParserImpl extends
* method. * method.
* *
* @param matchnum match group number to be retrieved * @param matchnum match group number to be retrieved
*
* @return the content of the <code>matchnum'th</code> group of the internal * @return the content of the <code>matchnum'th</code> group of the internal
* match or null if this method is called without a match having * match or null if this method is called without a match having
* been made. * been made.
@ -148,8 +143,10 @@ public abstract class RegexFTPFileEntryParserImpl extends
public String getGroupsAsString() { public String getGroupsAsString() {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
for (int i = 1; i <= this.result.groupCount(); i++) { for (int i = 1; i <= this.result.groupCount(); i++) {
b.append(i).append(") ").append(this.result.group(i)).append( b.append(i)
System.getProperty("line.separator")); .append(") ")
.append(this.result.group(i))
.append(System.getProperty("line.separator"));
} }
return b.toString(); return b.toString();
} }
@ -157,25 +154,26 @@ public abstract class RegexFTPFileEntryParserImpl extends
/** /**
* Alter the current regular expression being utilised for entry parsing * Alter the current regular expression being utilised for entry parsing
* and create a new {@link Pattern} instance. * and create a new {@link Pattern} instance.
*
* @param regex The new regular expression * @param regex The new regular expression
* @return true * @return true
* @since 2.0
* @throws IllegalArgumentException if the regex cannot be compiled * @throws IllegalArgumentException if the regex cannot be compiled
* @since 2.0
*/ */
public boolean setRegex(final String regex) { public boolean setRegex(final String regex) {
compileRegex(regex, 0); compileRegex(regex, 0);
return true; return true;
} }
/** /**
* Alter the current regular expression being utilised for entry parsing * Alter the current regular expression being utilised for entry parsing
* and create a new {@link Pattern} instance. * and create a new {@link Pattern} instance.
*
* @param regex The new regular expression * @param regex The new regular expression
* @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none. * @param flags the flags to apply, see {@link Pattern#compile(String, int)}. Use 0 for none.
* @return true * @return true
* @since 3.4
* @throws IllegalArgumentException if the regex cannot be compiled * @throws IllegalArgumentException if the regex cannot be compiled
* @since 3.4
*/ */
public boolean setRegex(final String regex, final int flags) { public boolean setRegex(final String regex, final int flags) {
compileRegex(regex, flags); compileRegex(regex, flags);

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp.parser; package org.apache.commons.net.ftp.parser;
import java.text.ParseException; import java.text.ParseException;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
@ -30,31 +31,28 @@ import org.apache.commons.net.ftp.FTPFile;
* This class is based on the logic of Daniel Savarese's * This class is based on the logic of Daniel Savarese's
* DefaultFTPListParser, but adapted to use regular expressions and to fit the * DefaultFTPListParser, but adapted to use regular expressions and to fit the
* new FTPFileEntryParser interface. * new FTPFileEntryParser interface.
*
* @version $Id: UnixFTPEntryParser.java 1781925 2017-02-06 16:43:40Z sebb $ * @version $Id: UnixFTPEntryParser.java 1781925 2017-02-06 16:43:40Z sebb $
* @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
*/ */
public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
{
static final String DEFAULT_DATE_FORMAT static final String DEFAULT_DATE_FORMAT = "MMM d yyyy"; //Nov 9 2001
= "MMM d yyyy"; //Nov 9 2001
static final String DEFAULT_RECENT_DATE_FORMAT static final String DEFAULT_RECENT_DATE_FORMAT = "MMM d HH:mm"; //Nov 9 20:06
= "MMM d HH:mm"; //Nov 9 20:06
static final String NUMERIC_DATE_FORMAT static final String NUMERIC_DATE_FORMAT = "yyyy-MM-dd HH:mm"; //2001-11-09 20:06
= "yyyy-MM-dd HH:mm"; //2001-11-09 20:06
// Suffixes used in Japanese listings after the numeric values // Suffixes used in Japanese listings after the numeric values
private static final String JA_MONTH = "\u6708"; private static final String JA_MONTH = "\u6708";
private static final String JA_DAY = "\u65e5"; private static final String JA_DAY = "\u65e5";
private static final String JA_YEAR = "\u5e74"; private static final String JA_YEAR = "\u5e74";
private static final String DEFAULT_DATE_FORMAT_JA private static final String DEFAULT_DATE_FORMAT_JA =
= "M'" + JA_MONTH + "' d'" + JA_DAY + "' yyyy'" + JA_YEAR + "'"; //6月 3日 2003年 "M'" + JA_MONTH + "' d'" + JA_DAY + "' yyyy'" + JA_YEAR + "'"; //6月 3日 2003年
private static final String DEFAULT_RECENT_DATE_FORMAT_JA private static final String DEFAULT_RECENT_DATE_FORMAT_JA =
= "M'" + JA_MONTH + "' d'" + JA_DAY + "' HH:mm"; //8月 17日 20:10 "M'" + JA_MONTH + "' d'" + JA_DAY + "' HH:mm"; //8月 17日 20:10
/** /**
* Some Linux distributions are now shipping an FTP server which formats * Some Linux distributions are now shipping an FTP server which formats
@ -69,10 +67,7 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* Steve Cohen - 2005-04-17 * Steve Cohen - 2005-04-17
*/ */
public static final FTPClientConfig NUMERIC_DATE_CONFIG = public static final FTPClientConfig NUMERIC_DATE_CONFIG =
new FTPClientConfig( new FTPClientConfig(FTPClientConfig.SYST_UNIX, NUMERIC_DATE_FORMAT, null);
FTPClientConfig.SYST_UNIX,
NUMERIC_DATE_FORMAT,
null);
/** /**
* this is the regular expression used by this parser. * this is the regular expression used by this parser.
@ -99,9 +94,8 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* this is not allowed for here as does not appear to be shown by FTP servers * this is not allowed for here as does not appear to be shown by FTP servers
* {@code @} file has extended attributes * {@code @} file has extended attributes
*/ */
private static final String REGEX = private static final String REGEX = "([bcdelfmpSs-])" // file type
"([bcdelfmpSs-])" // file type + "(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?" // permissions
+"(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\\+?" // permissions
+ "\\s*" // separator TODO why allow it to be omitted?? + "\\s*" // separator TODO why allow it to be omitted??
@ -124,13 +118,10 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* diacritics (e.g. umlaut) in some abbreviations. * diacritics (e.g. umlaut) in some abbreviations.
* Japanese uses numeric day and month with suffixes to distinguish them * Japanese uses numeric day and month with suffixes to distinguish them
* [d]dXX [d]dZZ * [d]dXX [d]dZZ
*/ */ + "(" + "(?:\\d+[-/]\\d+[-/]\\d+)" + // yyyy-mm-dd
+ "("+
"(?:\\d+[-/]\\d+[-/]\\d+)" + // yyyy-mm-dd
"|(?:\\S{3}\\s+\\d{1,2})" + // MMM [d]d "|(?:\\S{3}\\s+\\d{1,2})" + // MMM [d]d
"|(?:\\d{1,2}\\s+\\S{3})" + // [d]d MMM "|(?:\\d{1,2}\\s+\\S{3})" + // [d]d MMM
"|(?:\\d{1,2}" + JA_MONTH + "\\s+\\d{1,2}" + JA_DAY + ")"+ "|(?:\\d{1,2}" + JA_MONTH + "\\s+\\d{1,2}" + JA_DAY + ")" + ")"
")"
+ "\\s+" // separator + "\\s+" // separator
@ -138,14 +129,12 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
year (for non-recent standard format) - yyyy year (for non-recent standard format) - yyyy
or time (for numeric or recent standard format) [h]h:mm or time (for numeric or recent standard format) [h]h:mm
or Japanese year - yyyyXX or Japanese year - yyyyXX
*/ */ + "((?:\\d+(?::\\d+)?)|(?:\\d{4}" + JA_YEAR + "))" // (20)
+ "((?:\\d+(?::\\d+)?)|(?:\\d{4}" + JA_YEAR + "))" // (20)
+ "\\s" // separator + "\\s" // separator
+ "(.*)"; // the rest (21) + "(.*)"; // the rest (21)
// if true, leading spaces are trimmed from file names // if true, leading spaces are trimmed from file names
// this was the case for the original implementation // this was the case for the original implementation
final boolean trimLeadingSpaces; // package protected for access from test code final boolean trimLeadingSpaces; // package protected for access from test code
@ -153,13 +142,12 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
/** /**
* The default constructor for a UnixFTPEntryParser object. * The default constructor for a UnixFTPEntryParser object.
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
*/ */
public UnixFTPEntryParser() public UnixFTPEntryParser() {
{
this(null); this(null);
} }
@ -169,14 +157,13 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* *
* @param config The {@link FTPClientConfig configuration} object used to * @param config The {@link FTPClientConfig configuration} object used to
* configure this parser. * configure this parser.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
* @since 1.4 * @since 1.4
*/ */
public UnixFTPEntryParser(FTPClientConfig config) public UnixFTPEntryParser(FTPClientConfig config) {
{
this(config, false); this(config, false);
} }
@ -187,14 +174,13 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* @param config The {@link FTPClientConfig configuration} object used to * @param config The {@link FTPClientConfig configuration} object used to
* configure this parser. * configure this parser.
* @param trimLeadingSpaces if {@code true}, trim leading spaces from file names * @param trimLeadingSpaces if {@code true}, trim leading spaces from file names
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
* @since 3.4 * @since 3.4
*/ */
public UnixFTPEntryParser(FTPClientConfig config, boolean trimLeadingSpaces) public UnixFTPEntryParser(FTPClientConfig config, boolean trimLeadingSpaces) {
{
super(REGEX); super(REGEX);
configure(config); configure(config);
this.trimLeadingSpaces = trimLeadingSpaces; this.trimLeadingSpaces = trimLeadingSpaces;
@ -203,8 +189,7 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
/** /**
* Preparse the list to discard "total nnn" lines * Preparse the list to discard "total nnn" lines
*/ */
@Override @Override public List<String> preParse(List<String> original) {
public List<String> preParse(List<String> original) {
ListIterator<String> iter = original.listIterator(); ListIterator<String> iter = original.listIterator();
while (iter.hasNext()) { while (iter.hasNext()) {
String entry = iter.next(); String entry = iter.next();
@ -225,15 +210,13 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* @param entry A line of text from the file listing * @param entry A line of text from the file listing
* @return An FTPFile instance corresponding to the supplied entry * @return An FTPFile instance corresponding to the supplied entry
*/ */
@Override @Override public FTPFile parseFTPEntry(String entry) {
public FTPFile parseFTPEntry(String entry) {
FTPFile file = new FTPFile(); FTPFile file = new FTPFile();
file.setRawListing(entry); file.setRawListing(entry);
int type; int type;
boolean isDevice = false; boolean isDevice = false;
if (matches(entry)) if (matches(entry)) {
{
String typeStr = group(1); String typeStr = group(1);
String hardLinkCount = group(15); String hardLinkCount = group(15);
String usr = group(16); String usr = group(16);
@ -245,19 +228,16 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
name = name.replaceFirst("^\\s+", ""); name = name.replaceFirst("^\\s+", "");
} }
try try {
{
if (group(19).contains(JA_MONTH)) { // special processing for Japanese format if (group(19).contains(JA_MONTH)) { // special processing for Japanese format
FTPTimestampParserImpl jaParser = new FTPTimestampParserImpl(); FTPTimestampParserImpl jaParser = new FTPTimestampParserImpl();
jaParser.configure(new FTPClientConfig( jaParser.configure(new FTPClientConfig(FTPClientConfig.SYST_UNIX, DEFAULT_DATE_FORMAT_JA,
FTPClientConfig.SYST_UNIX, DEFAULT_DATE_FORMAT_JA, DEFAULT_RECENT_DATE_FORMAT_JA)); DEFAULT_RECENT_DATE_FORMAT_JA));
file.setTimestamp(jaParser.parseTimestamp(datestr)); file.setTimestamp(jaParser.parseTimestamp(datestr));
} else { } else {
file.setTimestamp(super.parseTimestamp(datestr)); file.setTimestamp(super.parseTimestamp(datestr));
} }
} } catch (ParseException e) {
catch (ParseException e)
{
// intentionally do nothing // intentionally do nothing
} }
@ -265,8 +245,7 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
// 'translucent' filesystems, of which a 'union' filesystem is one. // 'translucent' filesystems, of which a 'union' filesystem is one.
// bcdelfmpSs- // bcdelfmpSs-
switch (typeStr.charAt(0)) switch (typeStr.charAt(0)) {
{
case 'd': case 'd':
type = FTPFile.DIRECTORY_TYPE; type = FTPFile.DIRECTORY_TYPE;
break; break;
@ -292,33 +271,23 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
file.setType(type); file.setType(type);
int g = 4; int g = 4;
for (int access = 0; access < 3; access++, g += 4) for (int access = 0; access < 3; access++, g += 4) {
{
// Use != '-' to avoid having to check for suid and sticky bits // Use != '-' to avoid having to check for suid and sticky bits
file.setPermission(access, FTPFile.READ_PERMISSION, file.setPermission(access, FTPFile.READ_PERMISSION, (!group(g).equals("-")));
(!group(g).equals("-"))); file.setPermission(access, FTPFile.WRITE_PERMISSION, (!group(g + 1).equals("-")));
file.setPermission(access, FTPFile.WRITE_PERMISSION,
(!group(g + 1).equals("-")));
String execPerm = group(g + 2); String execPerm = group(g + 2);
if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0))) {
{
file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true); file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true);
} } else {
else
{
file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false); file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false);
} }
} }
if (!isDevice) if (!isDevice) {
{ try {
try
{
file.setHardLinkCount(Integer.parseInt(hardLinkCount)); file.setHardLinkCount(Integer.parseInt(hardLinkCount));
} } catch (NumberFormatException e) {
catch (NumberFormatException e)
{
// intentionally do nothing // intentionally do nothing
} }
} }
@ -326,35 +295,25 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
file.setUser(usr); file.setUser(usr);
file.setGroup(grp); file.setGroup(grp);
try try {
{
file.setSize(Long.parseLong(filesize)); file.setSize(Long.parseLong(filesize));
} } catch (NumberFormatException e) {
catch (NumberFormatException e)
{
// intentionally do nothing // intentionally do nothing
} }
// oddball cases like symbolic links, file names // oddball cases like symbolic links, file names
// with spaces in them. // with spaces in them.
if (type == FTPFile.SYMBOLIC_LINK_TYPE) if (type == FTPFile.SYMBOLIC_LINK_TYPE) {
{
int end = name.indexOf(" -> "); int end = name.indexOf(" -> ");
// Give up if no link indicator is present // Give up if no link indicator is present
if (end == -1) if (end == -1) {
{
file.setName(name); file.setName(name);
} } else {
else
{
file.setName(name.substring(0, end)); file.setName(name.substring(0, end));
file.setLink(name.substring(end + 4)); file.setLink(name.substring(end + 4));
} }
} else {
}
else
{
file.setName(name); file.setName(name);
} }
return file; return file;
@ -366,14 +325,11 @@ public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* Defines a default configuration to be used when this class is * Defines a default configuration to be used when this class is
* instantiated without a {@link FTPClientConfig FTPClientConfig} * instantiated without a {@link FTPClientConfig FTPClientConfig}
* parameter being specified. * parameter being specified.
*
* @return the default configuration for this parser. * @return the default configuration for this parser.
*/ */
@Override @Override protected FTPClientConfig getDefaultConfiguration() {
protected FTPClientConfig getDefaultConfiguration() { return new FTPClientConfig(FTPClientConfig.SYST_UNIX, DEFAULT_DATE_FORMAT,
return new FTPClientConfig(
FTPClientConfig.SYST_UNIX,
DEFAULT_DATE_FORMAT,
DEFAULT_RECENT_DATE_FORMAT); DEFAULT_RECENT_DATE_FORMAT);
} }
} }

@ -16,6 +16,7 @@
*/ */
package org.apache.commons.net.ftp.parser; package org.apache.commons.net.ftp.parser;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.text.ParseException; import java.text.ParseException;
@ -28,9 +29,12 @@ import org.apache.commons.net.ftp.FTPFile;
* Implementation FTPFileEntryParser and FTPFileListParser for VMS Systems. * Implementation FTPFileEntryParser and FTPFileListParser for VMS Systems.
* This is a sample of VMS LIST output * 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;1 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER]
* "1-JUN.LIS;2 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", * (RWED,RWED,RWED,RE)",
* "DATA.DIR;1 1/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)",
* <P><B> * <P><B>
* Note: VMSFTPEntryParser can only be instantiated through the * Note: VMSFTPEntryParser can only be instantiated through the
* DefaultFTPParserFactory by classname. It will not be chosen * DefaultFTPParserFactory by classname. It will not be chosen
@ -39,15 +43,12 @@ import org.apache.commons.net.ftp.FTPFile;
* <P> * <P>
* *
* @version $Id: VMSFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $ * @version $Id: VMSFTPEntryParser.java 1752660 2016-07-14 13:25:39Z sebb $
*
* @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
* @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory * @see org.apache.commons.net.ftp.parser.DefaultFTPFileEntryParserFactory
*/ */
public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl {
{
private static final String DEFAULT_DATE_FORMAT private static final String DEFAULT_DATE_FORMAT = "d-MMM-yyyy HH:mm:ss"; //9-NOV-2001 12:30:24
= "d-MMM-yyyy HH:mm:ss"; //9-NOV-2001 12:30:24
/** /**
* this is the regular expression used by this parser. * this is the regular expression used by this parser.
@ -55,23 +56,21 @@ public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
private static final String REGEX = private static final String REGEX =
"(.*?;[0-9]+)\\s*" //1 file and version "(.*?;[0-9]+)\\s*" //1 file and version
+ "(\\d+)/\\d+\\s*" //2 size/allocated + "(\\d+)/\\d+\\s*" //2 size/allocated
+"(\\S+)\\s+(\\S+)\\s+" //3+4 date and time + "(\\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 + "\\[(([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) + "\\([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]* ? // TODO - perhaps restrict permissions to [RWED]* ?
/** /**
* Constructor for a VMSFTPEntryParser object. * Constructor for a VMSFTPEntryParser object.
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
*/ */
public VMSFTPEntryParser() public VMSFTPEntryParser() {
{
this(null); this(null);
} }
@ -81,14 +80,13 @@ public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* *
* @param config The {@link FTPClientConfig configuration} object used to * @param config The {@link FTPClientConfig configuration} object used to
* configure this parser. * configure this parser.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
* @since 1.4 * @since 1.4
*/ */
public VMSFTPEntryParser(FTPClientConfig config) public VMSFTPEntryParser(FTPClientConfig config) {
{
super(REGEX); super(REGEX);
configure(config); configure(config);
} }
@ -103,34 +101,27 @@ public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* @param entry A line of text from the file listing * @param entry A line of text from the file listing
* @return An FTPFile instance corresponding to the supplied entry * @return An FTPFile instance corresponding to the supplied entry
*/ */
@Override @Override public FTPFile parseFTPEntry(String entry) {
public FTPFile parseFTPEntry(String entry)
{
//one block in VMS equals 512 bytes //one block in VMS equals 512 bytes
long longBlock = 512; long longBlock = 512;
if (matches(entry)) if (matches(entry)) {
{
FTPFile f = new FTPFile(); FTPFile f = new FTPFile();
f.setRawListing(entry); f.setRawListing(entry);
String name = group(1); String name = group(1);
String size = group(2); String size = group(2);
String datestr = group(3)+" "+group(4); String datestr = group(3) + " " + group(4);
String owner = group(5); String owner = group(5);
String permissions[] = new String[3]; String permissions[] = new String[3];
permissions[0]= group(9); permissions[0] = group(9);
permissions[1]= group(10); permissions[1] = group(10);
permissions[2]= group(11); permissions[2] = group(11);
try try {
{
f.setTimestamp(super.parseTimestamp(datestr)); f.setTimestamp(super.parseTimestamp(datestr));
} } catch (ParseException e) {
catch (ParseException e)
{
// intentionally do nothing // intentionally do nothing
} }
String grp; String grp;
String user; String user;
StringTokenizer t = new StringTokenizer(owner, ","); StringTokenizer t = new StringTokenizer(owner, ",");
@ -148,22 +139,16 @@ public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
user = null; user = null;
} }
if (name.lastIndexOf(".DIR") != -1) if (name.lastIndexOf(".DIR") != -1) {
{
f.setType(FTPFile.DIRECTORY_TYPE); f.setType(FTPFile.DIRECTORY_TYPE);
} } else {
else
{
f.setType(FTPFile.FILE_TYPE); f.setType(FTPFile.FILE_TYPE);
} }
//set FTPFile name //set FTPFile name
//Check also for versions to be returned or not //Check also for versions to be returned or not
if (isVersioning()) if (isVersioning()) {
{
f.setName(name); f.setName(name);
} } else {
else
{
name = name.substring(0, name.lastIndexOf(";")); name = name.substring(0, name.lastIndexOf(";"));
f.setName(name); f.setName(name);
} }
@ -181,13 +166,12 @@ public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
//R (read) W (write) E (execute) D (delete) //R (read) W (write) E (execute) D (delete)
//iterate for OWNER GROUP WORLD permissions //iterate for OWNER GROUP WORLD permissions
for (int access = 0; access < 3; access++) for (int access = 0; access < 3; access++) {
{
String permission = permissions[access]; String permission = permissions[access];
f.setPermission(access, FTPFile.READ_PERMISSION, permission.indexOf('R')>=0); f.setPermission(access, FTPFile.READ_PERMISSION, permission.indexOf('R') >= 0);
f.setPermission(access, FTPFile.WRITE_PERMISSION, permission.indexOf('W')>=0); f.setPermission(access, FTPFile.WRITE_PERMISSION, permission.indexOf('W') >= 0);
f.setPermission(access, FTPFile.EXECUTE_PERMISSION, permission.indexOf('E')>=0); f.setPermission(access, FTPFile.EXECUTE_PERMISSION, permission.indexOf('E') >= 0);
} }
return f; return f;
@ -195,7 +179,6 @@ public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
return null; return null;
} }
/** /**
* Reads the next entry using the supplied BufferedReader object up to * Reads the next entry using the supplied BufferedReader object up to
* whatever delemits one entry from the next. This parser cannot use * whatever delemits one entry from the next. This parser cannot use
@ -204,25 +187,20 @@ public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* *
* @param reader The BufferedReader object from which entries are to be * @param reader The BufferedReader object from which entries are to be
* read. * read.
*
* @return A string representing the next ftp entry or null if none found. * @return A string representing the next ftp entry or null if none found.
* @throws IOException thrown on any IO Error reading from the reader. * @throws IOException thrown on any IO Error reading from the reader.
*/ */
@Override @Override public String readNextEntry(BufferedReader reader) throws IOException {
public String readNextEntry(BufferedReader reader) throws IOException
{
String line = reader.readLine(); String line = reader.readLine();
StringBuilder entry = new StringBuilder(); StringBuilder entry = new StringBuilder();
while (line != null) while (line != null) {
{
if (line.startsWith("Directory") || line.startsWith("Total")) { if (line.startsWith("Directory") || line.startsWith("Total")) {
line = reader.readLine(); line = reader.readLine();
continue; continue;
} }
entry.append(line); entry.append(line);
if (line.trim().endsWith(")")) if (line.trim().endsWith(")")) {
{
break; break;
} }
line = reader.readLine(); line = reader.readLine();
@ -238,32 +216,29 @@ public class VMSFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
* Defines a default configuration to be used when this class is * Defines a default configuration to be used when this class is
* instantiated without a {@link FTPClientConfig FTPClientConfig} * instantiated without a {@link FTPClientConfig FTPClientConfig}
* parameter being specified. * parameter being specified.
*
* @return the default configuration for this parser. * @return the default configuration for this parser.
*/ */
@Override @Override protected FTPClientConfig getDefaultConfiguration() {
protected FTPClientConfig getDefaultConfiguration() { return new FTPClientConfig(FTPClientConfig.SYST_VMS, DEFAULT_DATE_FORMAT, null);
return new FTPClientConfig(
FTPClientConfig.SYST_VMS,
DEFAULT_DATE_FORMAT,
null);
} }
// DEPRECATED METHODS - for API compatibility only - DO NOT USE // DEPRECATED METHODS - for API compatibility only - DO NOT USE
/** /**
* DO NOT USE * DO NOT USE
*
* @param listStream the stream * @param listStream the stream
* @return the array of files * @return the array of files
* @throws IOException on error * @throws IOException on error
* @deprecated (2.2) No other FTPFileEntryParser implementations have this method. * @deprecated (2.2) No other FTPFileEntryParser implementations have this method.
*/ */
@Deprecated @Deprecated public FTPFile[] parseFileList(java.io.InputStream listStream) throws IOException {
public FTPFile[] parseFileList(java.io.InputStream listStream) throws IOException { org.apache.commons.net.ftp.FTPListParseEngine engine =
org.apache.commons.net.ftp.FTPListParseEngine engine = new org.apache.commons.net.ftp.FTPListParseEngine(this); new org.apache.commons.net.ftp.FTPListParseEngine(this);
engine.readServerList(listStream, null); engine.readServerList(listStream, null);
return engine.getFiles(); return engine.getFiles();
} }
} }
/* Emacs configuration /* Emacs configuration

@ -34,32 +34,31 @@ import org.apache.commons.net.ftp.FTPClientConfig;
* *
* This is a sample of VMS LIST output * 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;1 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER]
* "1-JUN.LIS;2 9/9 2-JUN-1998 07:32:04 [GROUP,OWNER] (RWED,RWED,RWED,RE)", * (RWED,RWED,RWED,RE)",
* "DATA.DIR;1 1/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)",
* <P> * <P>
* *
* @version $Id: VMSVersioningFTPEntryParser.java 1747119 2016-06-07 02:22:24Z ggregory $ * @version $Id: VMSVersioningFTPEntryParser.java 1747119 2016-06-07 02:22:24Z ggregory $
*
* @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions) * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
*/ */
public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser {
{
private final Pattern _preparse_pattern_; private final Pattern _preparse_pattern_;
private static final String PRE_PARSE_REGEX = private static final String PRE_PARSE_REGEX = "(.*?);([0-9]+)\\s*.*";
"(.*?);([0-9]+)\\s*.*";
/** /**
* Constructor for a VMSFTPEntryParser object. * Constructor for a VMSFTPEntryParser object.
* *
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
*/ */
public VMSVersioningFTPEntryParser() public VMSVersioningFTPEntryParser() {
{
this(null); this(null);
} }
@ -69,27 +68,21 @@ public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser
* *
* @param config The {@link FTPClientConfig configuration} object used to * @param config The {@link FTPClientConfig configuration} object used to
* configure this parser. * configure this parser.
* @throws IllegalArgumentException * @throws IllegalArgumentException Thrown if the regular expression is unparseable. Should not
* Thrown if the regular expression is unparseable. Should not be seen * be seen
* under normal conditions. It it is seen, this is a sign that * under normal conditions. It it is seen, this is a sign that
* <code>REGEX</code> is not a valid regular expression. * <code>REGEX</code> is not a valid regular expression.
* @since 1.4 * @since 1.4
*/ */
public VMSVersioningFTPEntryParser(FTPClientConfig config) public VMSVersioningFTPEntryParser(FTPClientConfig config) {
{
super(); super();
configure(config); configure(config);
try try {
{
//_preparse_matcher_ = new Perl5Matcher(); //_preparse_matcher_ = new Perl5Matcher();
_preparse_pattern_ = Pattern.compile(PRE_PARSE_REGEX); _preparse_pattern_ = Pattern.compile(PRE_PARSE_REGEX);
} catch (PatternSyntaxException pse) {
throw new IllegalArgumentException("Unparseable regex supplied: " + PRE_PARSE_REGEX);
} }
catch (PatternSyntaxException pse)
{
throw new IllegalArgumentException (
"Unparseable regex supplied: " + PRE_PARSE_REGEX);
}
} }
/** /**
@ -98,11 +91,9 @@ public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser
* multiple files with the same name to remove the duplicates .. * multiple files with the same name to remove the duplicates ..
* *
* @param original Original list * @param original Original list
*
* @return Original list purged of duplicates * @return Original list purged of duplicates
*/ */
@Override @Override public List<String> preParse(List<String> original) {
public List<String> preParse(List<String> original) {
HashMap<String, Integer> existingEntries = new HashMap<String, Integer>(); HashMap<String, Integer> existingEntries = new HashMap<String, Integer>();
ListIterator<String> iter = original.listIterator(); ListIterator<String> iter = original.listIterator();
while (iter.hasNext()) { while (iter.hasNext()) {
@ -123,7 +114,6 @@ public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser
} }
existingEntries.put(name, nv); existingEntries.put(name, nv);
} }
} }
// we've now removed all entries less than with less than the largest // we've now removed all entries less than with less than the largest
// version number for each name that were listed after the largest. // version number for each name that were listed after the largest.
@ -145,17 +135,13 @@ public class VMSVersioningFTPEntryParser extends VMSFTPEntryParser
} }
} }
} }
} }
return original; return original;
} }
@Override protected boolean isVersioning() {
@Override
protected boolean isVersioning() {
return true; return true;
} }
} }
/* Emacs configuration /* Emacs configuration

@ -28,18 +28,17 @@ import java.io.Reader;
* *
* @since 3.0 * @since 3.0
*/ */
public final class CRLFLineReader extends BufferedReader public final class CRLFLineReader extends BufferedReader {
{
private static final char LF = '\n'; private static final char LF = '\n';
private static final char CR = '\r'; private static final char CR = '\r';
/** /**
* Creates a CRLFLineReader that wraps an existing Reader * Creates a CRLFLineReader that wraps an existing Reader
* input source. * input source.
*
* @param reader The Reader input source. * @param reader The Reader input source.
*/ */
public CRLFLineReader(Reader reader) public CRLFLineReader(Reader reader) {
{
super(reader); super(reader);
} }
@ -47,18 +46,17 @@ public final class CRLFLineReader extends BufferedReader
* Read a line of text. * Read a line of text.
* A line is considered to be terminated by carriage return followed immediately by a linefeed. * A line is considered to be terminated by carriage return followed immediately by a linefeed.
* This contrasts with BufferedReader which also allows other combinations. * This contrasts with BufferedReader which also allows other combinations.
*
* @since 3.0 * @since 3.0
*/ */
@Override @Override public String readLine() throws IOException {
public String readLine() throws IOException {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
int intch; int intch;
boolean prevWasCR = false; boolean prevWasCR = false;
synchronized(lock) { // make thread-safe (hopefully!) synchronized (lock) { // make thread-safe (hopefully!)
while((intch = read()) != -1) while ((intch = read()) != -1) {
{
if (prevWasCR && intch == LF) { if (prevWasCR && intch == LF) {
return sb.substring(0, sb.length()-1); return sb.substring(0, sb.length() - 1);
} }
if (intch == CR) { if (intch == CR) {
prevWasCR = true; prevWasCR = true;

@ -32,21 +32,18 @@ import org.apache.commons.net.util.ListenerList;
* reasons and also because multiple listeners cannot be registered given * reasons and also because multiple listeners cannot be registered given
* that the methods are static. * that the methods are static.
* *
* * @version $Id: CopyStreamAdapter.java 1741829 2016-05-01 00:24:44Z sebb $
* @see CopyStreamEvent * @see CopyStreamEvent
* @see CopyStreamListener * @see CopyStreamListener
* @see Util * @see Util
* @version $Id: CopyStreamAdapter.java 1741829 2016-05-01 00:24:44Z sebb $
*/ */
public class CopyStreamAdapter implements CopyStreamListener public class CopyStreamAdapter implements CopyStreamListener {
{
private final ListenerList internalListeners; private final ListenerList internalListeners;
/** /**
* Creates a new copyStreamAdapter. * Creates a new copyStreamAdapter.
*/ */
public CopyStreamAdapter() public CopyStreamAdapter() {
{
internalListeners = new ListenerList(); internalListeners = new ListenerList();
} }
@ -57,14 +54,12 @@ public class CopyStreamAdapter implements CopyStreamListener
* transferred in the last write. The CopyStreamAdapater will relay * transferred in the last write. The CopyStreamAdapater will relay
* the event to all of its registered listeners, listing itself as the * the event to all of its registered listeners, listing itself as the
* source of the event. * source of the event.
*
* @param event The CopyStreamEvent fired by the copying of a block of * @param event The CopyStreamEvent fired by the copying of a block of
* bytes. * bytes.
*/ */
@Override @Override public void bytesTransferred(CopyStreamEvent event) {
public void bytesTransferred(CopyStreamEvent event) for (EventListener listener : internalListeners) {
{
for (EventListener listener : internalListeners)
{
((CopyStreamListener) (listener)).bytesTransferred(event); ((CopyStreamListener) (listener)).bytesTransferred(event);
} }
} }
@ -76,6 +71,7 @@ public class CopyStreamAdapter implements CopyStreamListener
* transfer. The CopyStreamAdapater will create a CopyStreamEvent * transfer. The CopyStreamAdapater will create a CopyStreamEvent
* from the arguments and relay the event to all of its registered * from the arguments and relay the event to all of its registered
* listeners, listing itself as the source of the event. * listeners, listing itself as the source of the event.
*
* @param totalBytesTransferred The total number of bytes transferred * @param totalBytesTransferred The total number of bytes transferred
* so far by the copy operation. * so far by the copy operation.
* @param bytesTransferred The number of bytes copied by the most recent * @param bytesTransferred The number of bytes copied by the most recent
@ -84,14 +80,11 @@ public class CopyStreamAdapter implements CopyStreamListener
* This may be equal to CopyStreamEvent.UNKNOWN_STREAM_SIZE if * This may be equal to CopyStreamEvent.UNKNOWN_STREAM_SIZE if
* the size is unknown. * the size is unknown.
*/ */
@Override @Override public void bytesTransferred(long totalBytesTransferred, int bytesTransferred,
public void bytesTransferred(long totalBytesTransferred, long streamSize) {
int bytesTransferred, long streamSize) for (EventListener listener : internalListeners) {
{ ((CopyStreamListener) (listener)).bytesTransferred(totalBytesTransferred, bytesTransferred,
for (EventListener listener : internalListeners) streamSize);
{
((CopyStreamListener) (listener)).bytesTransferred(
totalBytesTransferred, bytesTransferred, streamSize);
} }
} }
@ -99,20 +92,20 @@ public class CopyStreamAdapter implements CopyStreamListener
* Registers a CopyStreamListener to receive CopyStreamEvents. * Registers a CopyStreamListener to receive CopyStreamEvents.
* Although this method is not declared to be synchronized, it is * Although this method is not declared to be synchronized, it is
* implemented in a thread safe manner. * implemented in a thread safe manner.
*
* @param listener The CopyStreamlistener to register. * @param listener The CopyStreamlistener to register.
*/ */
public void addCopyStreamListener(CopyStreamListener listener) public void addCopyStreamListener(CopyStreamListener listener) {
{
internalListeners.addListener(listener); internalListeners.addListener(listener);
} }
/** /**
* Unregisters a CopyStreamListener. Although this method is not * Unregisters a CopyStreamListener. Although this method is not
* synchronized, it is implemented in a thread safe manner. * synchronized, it is implemented in a thread safe manner.
*
* @param listener The CopyStreamlistener to unregister. * @param listener The CopyStreamlistener to unregister.
*/ */
public void removeCopyStreamListener(CopyStreamListener listener) public void removeCopyStreamListener(CopyStreamListener listener) {
{
internalListeners.removeListener(listener); internalListeners.removeListener(listener);
} }
} }

@ -25,14 +25,12 @@ import java.util.EventObject;
* transferred by the write triggering the event as well as the total * transferred by the write triggering the event as well as the total
* number of bytes transferred so far by the copy operation. * 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 CopyStreamListener
* @see CopyStreamAdapter * @see CopyStreamAdapter
* @see Util * @see Util
* @version $Id: CopyStreamEvent.java 1652801 2015-01-18 17:10:05Z sebb $
*/ */
public class CopyStreamEvent extends EventObject public class CopyStreamEvent extends EventObject {
{
private static final long serialVersionUID = -964927635655051867L; private static final long serialVersionUID = -964927635655051867L;
/** /**
@ -46,6 +44,7 @@ public class CopyStreamEvent extends EventObject
/** /**
* Creates a new CopyStreamEvent instance. * Creates a new CopyStreamEvent instance.
*
* @param source The source of the event. * @param source The source of the event.
* @param totalBytesTransferred The total number of bytes transferred so * @param totalBytesTransferred The total number of bytes transferred so
* far during a copy operation. * far during a copy operation.
@ -55,9 +54,8 @@ public class CopyStreamEvent extends EventObject
* This may be set to <code>UNKNOWN_STREAM_SIZE</code> if the * This may be set to <code>UNKNOWN_STREAM_SIZE</code> if the
* size is unknown. * size is unknown.
*/ */
public CopyStreamEvent(Object source, long totalBytesTransferred, public CopyStreamEvent(Object source, long totalBytesTransferred, int bytesTransferred,
int bytesTransferred, long streamSize) long streamSize) {
{
super(source); super(source);
this.bytesTransferred = bytesTransferred; this.bytesTransferred = bytesTransferred;
this.totalBytesTransferred = totalBytesTransferred; this.totalBytesTransferred = totalBytesTransferred;
@ -67,22 +65,22 @@ public class CopyStreamEvent extends EventObject
/** /**
* Returns the number of bytes transferred by the write that triggered * Returns the number of bytes transferred by the write that triggered
* the event. * the event.
*
* @return The number of bytes transferred by the write that triggered * @return The number of bytes transferred by the write that triggered
* the vent. * the vent.
*/ */
public int getBytesTransferred() public int getBytesTransferred() {
{
return bytesTransferred; return bytesTransferred;
} }
/** /**
* Returns the total number of bytes transferred so far by the copy * Returns the total number of bytes transferred so far by the copy
* operation. * operation.
*
* @return The total number of bytes transferred so far by the copy * @return The total number of bytes transferred so far by the copy
* operation. * operation.
*/ */
public long getTotalBytesTransferred() public long getTotalBytesTransferred() {
{
return totalBytesTransferred; return totalBytesTransferred;
} }
@ -90,22 +88,26 @@ public class CopyStreamEvent extends EventObject
* Returns the size of the stream being copied. * Returns the size of the stream being copied.
* This may be set to <code>UNKNOWN_STREAM_SIZE</code> if the * This may be set to <code>UNKNOWN_STREAM_SIZE</code> if the
* size is unknown. * size is unknown.
*
* @return The size of the stream being copied. * @return The size of the stream being copied.
*/ */
public long getStreamSize() public long getStreamSize() {
{
return streamSize; return streamSize;
} }
/** /**
* @since 3.0 * @since 3.0
*/ */
@Override @Override public String toString() {
public String toString(){ return getClass().getName()
return getClass().getName() + "[source=" + source + "[source="
+ ", total=" + totalBytesTransferred + source
+ ", bytes=" + bytesTransferred + ", total="
+ ", size=" + streamSize + totalBytesTransferred
+ ", bytes="
+ bytesTransferred
+ ", size="
+ streamSize
+ "]"; + "]";
} }
} }

@ -24,26 +24,24 @@ import java.io.IOException;
* copyStream() methods. It stores the number of bytes confirmed to * copyStream() methods. It stores the number of bytes confirmed to
* have been transferred before an I/O error as well as the IOException * have been transferred before an I/O error as well as the IOException
* responsible for the failure of a copy operation. * responsible for the failure of a copy operation.
* @see Util *
* @version $Id: CopyStreamException.java 1299238 2012-03-10 17:12:28Z sebb $ * @version $Id: CopyStreamException.java 1299238 2012-03-10 17:12:28Z sebb $
* @see Util
*/ */
public class CopyStreamException extends IOException public class CopyStreamException extends IOException {
{
private static final long serialVersionUID = -2602899129433221532L; private static final long serialVersionUID = -2602899129433221532L;
private final long totalBytesTransferred; private final long totalBytesTransferred;
/** /**
* Creates a new CopyStreamException instance. * Creates a new CopyStreamException instance.
*
* @param message A message describing the error. * @param message A message describing the error.
* @param bytesTransferred The total number of bytes transferred before * @param bytesTransferred The total number of bytes transferred before
* an exception was thrown in a copy operation. * an exception was thrown in a copy operation.
* @param exception The IOException thrown during a copy operation. * @param exception The IOException thrown during a copy operation.
*/ */
public CopyStreamException(String message, public CopyStreamException(String message, long bytesTransferred, IOException exception) {
long bytesTransferred,
IOException exception)
{
super(message); super(message);
initCause(exception); // merge this into super() call once we need 1.6+ initCause(exception); // merge this into super() call once we need 1.6+
totalBytesTransferred = bytesTransferred; totalBytesTransferred = bytesTransferred;
@ -52,20 +50,20 @@ public class CopyStreamException extends IOException
/** /**
* Returns the total number of bytes confirmed to have * Returns the total number of bytes confirmed to have
* been transferred by a failed copy operation. * been transferred by a failed copy operation.
*
* @return The total number of bytes confirmed to have * @return The total number of bytes confirmed to have
* been transferred by a failed copy operation. * been transferred by a failed copy operation.
*/ */
public long getTotalBytesTransferred() public long getTotalBytesTransferred() {
{
return totalBytesTransferred; return totalBytesTransferred;
} }
/** /**
* Returns the IOException responsible for the failure of a copy operation. * Returns the IOException responsible for the failure of a copy operation.
*
* @return The IOException responsible for the failure of a copy operation. * @return The IOException responsible for the failure of a copy operation.
*/ */
public IOException getIOException() public IOException getIOException() {
{
return (IOException) getCause(); // cast is OK because it was initialised with an IOException return (IOException) getCause(); // cast is OK because it was initialised with an IOException
} }
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save