and add some JUnit tests of the new configuration stuff. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@278372 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -14,6 +14,7 @@ | |||||
| <property name="tstamp.format" value="yyyy-MM-dd HH:mm"/> | <property name="tstamp.format" value="yyyy-MM-dd HH:mm"/> | ||||
| <property name="server.timestamp.granularity.millis" value="60000"/> | <property name="server.timestamp.granularity.millis" value="60000"/> | ||||
| <property name="ftp.server.timezone" value="GMT"/> | <property name="ftp.server.timezone" value="GMT"/> | ||||
| <property name="ftp.listing.file" value="/dev/null"/> | |||||
| <fileset dir="${tmp.get.dir}" id="fileset-destination-with-selector"> | <fileset dir="${tmp.get.dir}" id="fileset-destination-with-selector"> | ||||
| <include name="alpha/**"/> | <include name="alpha/**"/> | ||||
| @@ -191,5 +192,59 @@ | |||||
| </fileset> | </fileset> | ||||
| </ftp> | </ftp> | ||||
| </target> | </target> | ||||
| <target name="configuration.1"> | |||||
| <ftp action="list" | |||||
| server="${ftp.host}" | |||||
| userid="${ftp.user}" | |||||
| password="${ftp.password}" | |||||
| separator="${ftp.filesep}" | |||||
| remotedir="${tmp.remote}" | |||||
| serverTimeZoneConfig="${ftp.server.timezone}" | |||||
| listing="${ftp.listing.file}" | |||||
| > | |||||
| <fileset dir="${tmp.local}"/> | |||||
| </ftp> | |||||
| </target> | |||||
| <target name="configuration.2"> | |||||
| <ftp action="list" | |||||
| server="${ftp.host}" | |||||
| userid="${ftp.user}" | |||||
| password="${ftp.password}" | |||||
| separator="${ftp.filesep}" | |||||
| remotedir="${tmp.remote}" | |||||
| serverTimeZoneConfig="${ftp.server.timezone}" | |||||
| listing="${ftp.listing.file}" | |||||
| systemTypeKey="WINDOWS" | |||||
| > | |||||
| <fileset dir="${tmp.local}"/> | |||||
| </ftp> | |||||
| </target> | |||||
| <target name="configuration.3"> | |||||
| <ftp action="list" | |||||
| server="${ftp.host}" | |||||
| userid="${ftp.user}" | |||||
| password="${ftp.password}" | |||||
| separator="${ftp.filesep}" | |||||
| remotedir="${tmp.remote}" | |||||
| defaultDateFormatConfig="yyyy/MM/dd HH:mm" | |||||
| listing="${ftp.listing.file}" | |||||
| systemTypeKey="UNIX" | |||||
| > | |||||
| <fileset dir="${tmp.local}"/> | |||||
| </ftp> | |||||
| </target> | |||||
| <target name="configuration.none"> | |||||
| <ftp action="list" | |||||
| server="${ftp.host}" | |||||
| userid="${ftp.user}" | |||||
| password="${ftp.password}" | |||||
| separator="${ftp.filesep}" | |||||
| remotedir="${tmp.remote}" | |||||
| listing="${ftp.listing.file}" | |||||
| > | |||||
| <fileset dir="${tmp.local}"/> | |||||
| </ftp> | |||||
| </target> | |||||
| </project> | </project> | ||||
| @@ -101,6 +101,7 @@ public class FTP | |||||
| private boolean verbose = false; | private boolean verbose = false; | ||||
| private boolean newerOnly = false; | private boolean newerOnly = false; | ||||
| private long timeDiffMillis = 0; | private long timeDiffMillis = 0; | ||||
| private long granularityMillis = 0L; | |||||
| private boolean timeDiffAuto = false; | private boolean timeDiffAuto = false; | ||||
| private int action = SEND_FILES; | private int action = SEND_FILES; | ||||
| private Vector filesets = new Vector(); | private Vector filesets = new Vector(); | ||||
| @@ -114,14 +115,13 @@ public class FTP | |||||
| private boolean preserveLastModified = false; | private boolean preserveLastModified = false; | ||||
| private String chmod = null; | private String chmod = null; | ||||
| private String umask = null; | private String umask = null; | ||||
| private String systemTypeKey = null; | |||||
| private FTPSystemType systemTypeKey = FTPSystemType.getDefault(); | |||||
| private String defaultDateFormatConfig = null; | private String defaultDateFormatConfig = null; | ||||
| private String recentDateFormatConfig = null; | private String recentDateFormatConfig = null; | ||||
| private String serverLanguageCodeConfig = null; | private String serverLanguageCodeConfig = null; | ||||
| private String serverTimeZoneConfig = null; | private String serverTimeZoneConfig = null; | ||||
| private String shortMonthNamesConfig = null; | private String shortMonthNamesConfig = null; | ||||
| private String timestampGranularity = null; | |||||
| private long serverTimestampGranularity = 0L; | |||||
| private Granularity timestampGranularity = Granularity.getDefault(); | |||||
| private boolean isConfigurationSet = false; | private boolean isConfigurationSet = false; | ||||
| protected static final String[] ACTION_STRS = { | protected static final String[] ACTION_STRS = { | ||||
| @@ -1268,8 +1268,8 @@ public class FTP | |||||
| * the default value of null will be kept. | * the default value of null will be kept. | ||||
| * @see org.apache.commons.net.ftp.FTPClientConfig | * @see org.apache.commons.net.ftp.FTPClientConfig | ||||
| */ | */ | ||||
| public void setSystemTypeKey(String systemKey) { | |||||
| if (systemKey != null && !systemKey.equals("")) | |||||
| public void setSystemTypeKey(FTPSystemType systemKey) { | |||||
| if (systemKey != null && !systemKey.getValue().equals("")) | |||||
| { | { | ||||
| this.systemTypeKey = systemKey; | this.systemTypeKey = systemKey; | ||||
| configurationHasBeenSet(); | configurationHasBeenSet(); | ||||
| @@ -1361,7 +1361,7 @@ public class FTP | |||||
| * @return Returns the systemTypeKey. | * @return Returns the systemTypeKey. | ||||
| */ | */ | ||||
| String getSystemTypeKey() { | String getSystemTypeKey() { | ||||
| return systemTypeKey; | |||||
| return systemTypeKey.getValue(); | |||||
| } | } | ||||
| /** | /** | ||||
| * @return Returns the defaultDateFormatConfig. | * @return Returns the defaultDateFormatConfig. | ||||
| @@ -1396,13 +1396,13 @@ public class FTP | |||||
| /** | /** | ||||
| * @return Returns the timestampGranularity. | * @return Returns the timestampGranularity. | ||||
| */ | */ | ||||
| String getTimestampGranularity() { | |||||
| Granularity getTimestampGranularity() { | |||||
| return timestampGranularity; | return timestampGranularity; | ||||
| } | } | ||||
| /** | /** | ||||
| * @param timestampGranularity The timestampGranularity to set. | * @param timestampGranularity The timestampGranularity to set. | ||||
| */ | */ | ||||
| public void setTimestampGranularity(String timestampGranularity) { | |||||
| public void setTimestampGranularity(Granularity timestampGranularity) { | |||||
| if (null == timestampGranularity || "".equals(timestampGranularity)) { | if (null == timestampGranularity || "".equals(timestampGranularity)) { | ||||
| return; | return; | ||||
| } | } | ||||
| @@ -1517,29 +1517,8 @@ public class FTP | |||||
| } | } | ||||
| } else { | } else { | ||||
| if (this.newerOnly) { | if (this.newerOnly) { | ||||
| if (action == SEND_FILES) { | |||||
| if ("NONE".equalsIgnoreCase(this.timestampGranularity)) | |||||
| { | |||||
| this.serverTimestampGranularity = 0L; | |||||
| } | |||||
| else if ("MINUTE".equalsIgnoreCase(this.timestampGranularity)) | |||||
| { | |||||
| this.serverTimestampGranularity = GRANULARITY_MINUTE; | |||||
| } | |||||
| else | |||||
| { | |||||
| this.serverTimestampGranularity = GRANULARITY_MINUTE; | |||||
| } | |||||
| } else if (action == GET_FILES) { | |||||
| if ("MINUTE".equalsIgnoreCase(this.timestampGranularity)) | |||||
| { | |||||
| this.serverTimestampGranularity = GRANULARITY_MINUTE; | |||||
| } | |||||
| else | |||||
| { | |||||
| this.serverTimestampGranularity = 0L; | |||||
| } | |||||
| } | |||||
| this.granularityMillis = | |||||
| this.timestampGranularity.getMilliseconds(action); | |||||
| } | } | ||||
| for (int i = 0; i < dsfiles.length; i++) { | for (int i = 0; i < dsfiles.length; i++) { | ||||
| switch (action) { | switch (action) { | ||||
| @@ -1799,13 +1778,13 @@ public class FTP | |||||
| if (this.action == SEND_FILES) { | if (this.action == SEND_FILES) { | ||||
| return remoteTimestamp | return remoteTimestamp | ||||
| + this.timeDiffMillis | + this.timeDiffMillis | ||||
| + this.serverTimestampGranularity | |||||
| + this.granularityMillis | |||||
| >= localTimestamp; | >= localTimestamp; | ||||
| } else { | } else { | ||||
| return localTimestamp | return localTimestamp | ||||
| >= remoteTimestamp | >= remoteTimestamp | ||||
| + this.timeDiffMillis | + this.timeDiffMillis | ||||
| + this.serverTimestampGranularity; | |||||
| + this.granularityMillis; | |||||
| } | } | ||||
| } | } | ||||
| @@ -2300,5 +2279,84 @@ public class FTP | |||||
| return SEND_FILES; | return SEND_FILES; | ||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * represents one of the valid timestamp adjustment values | |||||
| * recognized by the <code>timestampGranularity</code> attribute.<p> | |||||
| * A timestamp adjustment may be used in file transfers for checking | |||||
| * uptodateness. MINUTE means to add one minute to the server | |||||
| * timestamp. This is done because FTP servers typically list | |||||
| * timestamps HH:mm and client FileSystems typically use HH:mm:ss. | |||||
| * | |||||
| * The default is to use MINUTE for PUT actions and NONE for GET | |||||
| * actions, since GETs have the <code>preserveLastModified</code> | |||||
| * option, which takes care of the problem in most use cases where | |||||
| * this level of granularity is an issue. | |||||
| * | |||||
| */ | |||||
| public static class Granularity extends EnumeratedAttribute { | |||||
| private static final String[] VALID_GRANULARITIES = { | |||||
| "", "MINUTE", "NONE" | |||||
| }; | |||||
| /* | |||||
| * @return the list of valid Granularity values | |||||
| */ | |||||
| public String[] getValues() { | |||||
| // TODO Auto-generated method stub | |||||
| return VALID_GRANULARITIES; | |||||
| } | |||||
| /** | |||||
| * returns the number of milliseconds associated with | |||||
| * the attribute, which can vary in some cases depending | |||||
| * on the value of the action parameter. | |||||
| * @param action SEND_FILES or GET_FILES | |||||
| * @return the number of milliseconds associated with | |||||
| * the attribute, in the context of the supplied action | |||||
| */ | |||||
| public long getMilliseconds(int action) { | |||||
| String granularityU = getValue().toUpperCase(Locale.US); | |||||
| long granularity = 0L; | |||||
| if ("".equals(granularityU)) { | |||||
| if (action == SEND_FILES) { | |||||
| return GRANULARITY_MINUTE; | |||||
| } | |||||
| } else if ("MINUTE".equals(granularityU)) { | |||||
| return GRANULARITY_MINUTE; | |||||
| } | |||||
| return 0L; | |||||
| } | |||||
| static final Granularity getDefault() { | |||||
| Granularity g = new Granularity(); | |||||
| g.setValue(""); | |||||
| return g; | |||||
| } | |||||
| } | |||||
| /** | |||||
| * one of the valid system type keys recognized by the systemTypeKey | |||||
| * attribute. | |||||
| */ | |||||
| public static class FTPSystemType extends EnumeratedAttribute { | |||||
| private static final String[] VALID_SYSTEM_TYPES = { | |||||
| "", "UNIX", "VMS", "WINDOWS", "OS/2", "OS/400", | |||||
| "MVS" | |||||
| }; | |||||
| /* | |||||
| * @return the list of valid system types. | |||||
| */ | |||||
| public String[] getValues() { | |||||
| return VALID_SYSTEM_TYPES; | |||||
| } | |||||
| static final FTPSystemType getDefault() { | |||||
| FTPSystemType ftpst = new FTPSystemType(); | |||||
| ftpst.setValue(""); | |||||
| return ftpst; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -37,14 +37,17 @@ class FTPConfigurator { | |||||
| * @return the client as configured. | * @return the client as configured. | ||||
| */ | */ | ||||
| static FTPClient configure(FTPClient client, FTP task) { | static FTPClient configure(FTPClient client, FTP task) { | ||||
| task.log("custom configuration", Project.MSG_VERBOSE); | |||||
| FTPClientConfig config; | FTPClientConfig config; | ||||
| String systemTypeKey = task.getSystemTypeKey(); | String systemTypeKey = task.getSystemTypeKey(); | ||||
| if (systemTypeKey != null) { | |||||
| if (systemTypeKey != null && !"".equals(systemTypeKey)) { | |||||
| config = new FTPClientConfig(systemTypeKey); | config = new FTPClientConfig(systemTypeKey); | ||||
| task.log("custom config: system key = " | task.log("custom config: system key = " | ||||
| + systemTypeKey, Project.MSG_VERBOSE); | + systemTypeKey, Project.MSG_VERBOSE); | ||||
| } else { | } else { | ||||
| config = new FTPClientConfig(); | config = new FTPClientConfig(); | ||||
| task.log("custom config: system key = default (UNIX)", | |||||
| Project.MSG_VERBOSE); | |||||
| } | } | ||||
| String defaultDateFormatConfig = task.getDefaultDateFormatConfig(); | String defaultDateFormatConfig = task.getDefaultDateFormatConfig(); | ||||
| @@ -16,25 +16,23 @@ | |||||
| */ | */ | ||||
| package org.apache.tools.ant.taskdefs.optional.net; | package org.apache.tools.ant.taskdefs.optional.net; | ||||
| import java.io.File; | |||||
| import java.io.IOException; | |||||
| import java.util.Arrays; | |||||
| import java.util.HashMap; | |||||
| import java.util.Map; | |||||
| import java.util.Vector; | |||||
| import org.apache.commons.net.ftp.FTPClient; | |||||
| import org.apache.tools.ant.BuildEvent; | import org.apache.tools.ant.BuildEvent; | ||||
| import org.apache.tools.ant.BuildFileTest; | import org.apache.tools.ant.BuildFileTest; | ||||
| import org.apache.tools.ant.BuildListener; | |||||
| import org.apache.tools.ant.BuildLogger; | |||||
| import org.apache.tools.ant.DefaultLogger; | import org.apache.tools.ant.DefaultLogger; | ||||
| import org.apache.tools.ant.DirectoryScanner; | import org.apache.tools.ant.DirectoryScanner; | ||||
| import org.apache.tools.ant.Project; | |||||
| import org.apache.tools.ant.taskdefs.condition.Os; | |||||
| import org.apache.tools.ant.types.FileSet; | import org.apache.tools.ant.types.FileSet; | ||||
| import org.apache.tools.ant.taskdefs.optional.net.FTP; | |||||
| import org.apache.tools.ant.util.JavaEnvUtils; | |||||
| import org.apache.tools.ant.util.regexp.RegexpMatcher; | import org.apache.tools.ant.util.regexp.RegexpMatcher; | ||||
| import org.apache.tools.ant.util.regexp.RegexpMatcherFactory; | import org.apache.tools.ant.util.regexp.RegexpMatcherFactory; | ||||
| import org.apache.tools.ant.taskdefs.condition.Os; | |||||
| import java.io.File; | |||||
| import java.io.IOException; | |||||
| import java.util.Arrays; | |||||
| import java.util.Vector; | |||||
| import org.apache.commons.net.ftp.FTPClient; | |||||
| public class FTPTest extends BuildFileTest{ | public class FTPTest extends BuildFileTest{ | ||||
| // keep track of what operating systems are supported here. | // keep track of what operating systems are supported here. | ||||
| @@ -592,6 +590,42 @@ public class FTPTest extends BuildFileTest{ | |||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * This class enables the use of the log to count the number | |||||
| * of times a message has been emitted. | |||||
| */ | |||||
| private class LogCounter extends DefaultLogger { | |||||
| private Map searchMap = new HashMap(); | |||||
| private int matchCount; | |||||
| public void addLogMessageToSearch(String message) { | |||||
| searchMap.put(message, new Integer(0)); | |||||
| } | |||||
| /* | |||||
| * @param event the build event that is being logged. | |||||
| */ | |||||
| public void messageLogged(BuildEvent event) { | |||||
| String message = event.getMessage(); | |||||
| Integer mcnt = (Integer) searchMap.get(message); | |||||
| if (null != mcnt) { | |||||
| searchMap.put(message, new Integer(mcnt.intValue() + 1)); | |||||
| } | |||||
| super.messageLogged(event); | |||||
| } | |||||
| /** | |||||
| * @return the number of times that the looked for message was sent | |||||
| * to the log | |||||
| */ | |||||
| public int getMatchCount(String message) { | |||||
| Integer mcnt = (Integer) searchMap.get(message); | |||||
| if (null != mcnt) { | |||||
| return mcnt.intValue(); | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| } | |||||
| /** | /** | ||||
| * Tests the combination of the newer parameter and the | * Tests the combination of the newer parameter and the | ||||
| * serverTimezoneConfig parameter in the PUT action. The default | * serverTimezoneConfig parameter in the PUT action. The default | ||||
| @@ -619,7 +653,76 @@ public class FTPTest extends BuildFileTest{ | |||||
| getProject().executeTarget("timed.test.get.older"); | getProject().executeTarget("timed.test.get.older"); | ||||
| assertEquals(3, log.getCount()); | assertEquals(3, log.getCount()); | ||||
| } | } | ||||
| /** | |||||
| * Tests that the presence of one of the server config params forces | |||||
| * the system type to Unix if not specified. | |||||
| */ | |||||
| public void testConfiguration1() { | |||||
| int[] expectedCounts = { | |||||
| 1,1,0,1,0,0 | |||||
| }; | |||||
| performConfigTest("configuration.1", expectedCounts); | |||||
| } | |||||
| /** | |||||
| * Tests the systemTypeKey attribute. | |||||
| */ | |||||
| public void testConfiguration2() { | |||||
| int[] expectedCounts = { | |||||
| 1,0,0,1,1,0 | |||||
| }; | |||||
| performConfigTest("configuration.2", expectedCounts); | |||||
| } | |||||
| /** | |||||
| * Tests the systemTypeKey attribute with UNIX specified. | |||||
| */ | |||||
| public void testConfiguration3() { | |||||
| int[] expectedCounts = { | |||||
| 1,0,1,0,0,1 | |||||
| }; | |||||
| performConfigTest("configuration.3", expectedCounts); | |||||
| } | |||||
| /** | |||||
| * Tests the systemTypeKey attribute. | |||||
| */ | |||||
| public void testConfigurationNone() { | |||||
| int[] expectedCounts = { | |||||
| 0,0,0,0,0,0 | |||||
| }; | |||||
| performConfigTest("configuration.none", expectedCounts); | |||||
| } | |||||
| private void performConfigTest(String target, int[] expectedCounts) { | |||||
| String[] messages = new String[]{ | |||||
| "custom configuration", | |||||
| "custom config: system key = default (UNIX)", | |||||
| "custom config: system key = UNIX", | |||||
| "custom config: server time zone ID = " + getProject().getProperty("ftp.server.timezone"), | |||||
| "custom config: system key = WINDOWS", | |||||
| "custom config: default date format = yyyy/MM/dd HH:mm" | |||||
| }; | |||||
| LogCounter counter = new LogCounter(); | |||||
| for (int i=0; i < messages.length; i++) { | |||||
| counter.addLogMessageToSearch(messages[i]); | |||||
| } | |||||
| getProject().addBuildListener(counter); | |||||
| getProject().executeTarget(target); | |||||
| for (int i=0; i < messages.length; i++) { | |||||
| assertEquals("target "+target+":message "+ i, expectedCounts[i], counter.getMatchCount(messages[i])); | |||||
| } | |||||
| } | |||||
| /** | /** | ||||
| * this test is inspired by a user reporting that deletions of directories with the ftp task do not work | * this test is inspired by a user reporting that deletions of directories with the ftp task do not work | ||||
| */ | */ | ||||