diff --git a/docs/manual/OptionalTasks/ftp.html b/docs/manual/OptionalTasks/ftp.html index 918bdcbe3..93e45a5fd 100644 --- a/docs/manual/OptionalTasks/ftp.html +++ b/docs/manual/OptionalTasks/ftp.html @@ -192,6 +192,14 @@ coming from your ftp server (ls -l on the ftp prompt). (Note: Ignored on Java 1.1)
Retryable
interface) and executes that with possibility to
+ * retry the execution in case of IOException.
+ */
+public class RetryHandler {
+
+ private int retriesAllowed = 0;
+ private Task task;
+
+ /**
+ * Create a new RetryingHandler.
+ *
+ * @param retriesAllowed how many times to retry
+ * @param task the Ant task that is is executed from, used for logging only
+ */
+ public RetryHandler(int retriesAllowed, Task task) {
+ this.retriesAllowed = retriesAllowed;
+ this.task = task;
+ }
+
+ /**
+ * Execute the Retryable
code with specified number of retries.
+ *
+ * @param exe the code to execute
+ * @param desc some descriptive text for this piece of code, used for logging
+ * @throws IOException if the number of retries has exceeded the allowed limit
+ */
+ public void execute(Retryable exe, String desc) throws IOException {
+ int retries = 0;
+ while (true) {
+ try {
+ exe.execute();
+ break;
+ } catch (IOException e) {
+ retries++;
+ if (retries > this.retriesAllowed && this.retriesAllowed > -1) {
+ task.log("try #" + retries + ": IO error ("
+ + desc + "), number of maximum retries reached ("
+ + this.retriesAllowed + "), giving up", Project.MSG_WARN);
+ throw e;
+ } else {
+ task.log("try #" + retries + ": IO error (" + desc + "), retrying", Project.MSG_WARN);
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/org/apache/tools/ant/util/Retryable.java b/src/main/org/apache/tools/ant/util/Retryable.java
new file mode 100644
index 000000000..b4bf024c3
--- /dev/null
+++ b/src/main/org/apache/tools/ant/util/Retryable.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * 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.tools.ant.util;
+
+import java.io.IOException;
+
+
+/**
+ * Simple interface for executing a piece of code. Used for writing anonymous inner
+ * classes in FTP task for retry-on-IOException behaviour.
+ *
+ * @see RetryHandler
+ */
+public interface Retryable {
+ public static final int RETRY_FOREVER = -1;
+ void execute() throws IOException;
+
+}
\ No newline at end of file
diff --git a/src/testcases/org/apache/tools/ant/taskdefs/optional/net/FTPTest.java b/src/testcases/org/apache/tools/ant/taskdefs/optional/net/FTPTest.java
index 5bb22bb50..86f1aaf54 100644
--- a/src/testcases/org/apache/tools/ant/taskdefs/optional/net/FTPTest.java
+++ b/src/testcases/org/apache/tools/ant/taskdefs/optional/net/FTPTest.java
@@ -21,17 +21,21 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
+import java.util.Random;
import java.util.Vector;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.tools.ant.BuildEvent;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.ComponentHelper;
import org.apache.tools.ant.DefaultLogger;
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.util.RetryHandler;
+import org.apache.tools.ant.util.Retryable;
import org.apache.tools.ant.util.regexp.RegexpMatcher;
import org.apache.tools.ant.util.regexp.RegexpMatcherFactory;
@@ -779,6 +783,88 @@ public class FTPTest extends BuildFileTest{
public String resolveFile(String file) {
return super.resolveFile(file);
}
+ }
+
+
+ public abstract static class myRetryableFTP extends FTP {
+ private final int numberOfFailuresToSimulate;
+ private int simulatedFailuresLeft;
+
+ protected myRetryableFTP(int numberOfFailuresToSimulate) {
+ this.numberOfFailuresToSimulate = numberOfFailuresToSimulate;
+ this.simulatedFailuresLeft = numberOfFailuresToSimulate;
+ }
+ protected void getFile(FTPClient ftp, String dir, String filename)
+ throws IOException, BuildException
+ {
+ if (this.simulatedFailuresLeft > 0) {
+ this.simulatedFailuresLeft--;
+ throw new IOException("Simulated failure for testing");
+ }
+ super.getFile(ftp, dir, filename);
+ }
+ protected void executeRetryable(RetryHandler h, Retryable r,
+ String filename) throws IOException
+ {
+ this.simulatedFailuresLeft = this.numberOfFailuresToSimulate;
+ super.executeRetryable(h, r, filename);
+ }
}
+ public static class oneFailureFTP extends myRetryableFTP {
+ public oneFailureFTP() {
+ super(1);
+ }
+ }
+ public static class twoFailureFTP extends myRetryableFTP {
+ public twoFailureFTP() {
+ super(2);
+ }
+ }
+ public static class threeFailureFTP extends myRetryableFTP {
+ public threeFailureFTP() {
+ super(3);
+ }
+ }
+
+ public static class randomFailureFTP extends myRetryableFTP {
+ public randomFailureFTP() {
+ super(new Random(30000).nextInt());
+ }
+ }
+ public void testGetWithSelectorRetryable1() {
+ getProject().addTaskDefinition("ftp", oneFailureFTP.class);
+ try {
+ getProject().executeTarget("ftp-get-with-selector-retryable");
+ } catch (BuildException bx) {
+ fail("Two retries expected, failed after one.");
+ }
+ }
+ public void testGetWithSelectorRetryable2() {
+ getProject().addTaskDefinition("ftp", twoFailureFTP.class);
+ try {
+ getProject().executeTarget("ftp-get-with-selector-retryable");
+ } catch (BuildException bx) {
+ fail("Two retries expected, failed after two.");
+ }
+ }
+
+ public void testGetWithSelectorRetryable3() {
+ getProject().addTaskDefinition("ftp", threeFailureFTP.class);
+ try {
+ getProject().executeTarget("ftp-get-with-selector-retryable");
+ fail("Two retries expected, continued after two.");
+ } catch (BuildException bx) {
+ }
+ }
+ public void testGetWithSelectorRetryableRandom() {
+ getProject().addTaskDefinition("ftp", threeFailureFTP.class);
+ try {
+ getProject().setProperty("ftp.retries", "forever");
+ getProject().executeTarget("ftp-get-with-selector-retryable");
+ } catch (BuildException bx) {
+ fail("Retry forever specified, but failed.");
+ }
+ }
+
}