You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ro...@apache.org on 2017/01/10 14:18:20 UTC

[05/50] [abbrv] james-project git commit: JAMES-1877 Extract delays and max retries calculations from RemoteDelivery

JAMES-1877 Extract delays and max retries calculations from RemoteDelivery


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/8a8af97a
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/8a8af97a
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/8a8af97a

Branch: refs/heads/master
Commit: 8a8af97a5f569fb01f24b72bfbb8e481e4c26f26
Parents: 1193b6b
Author: Benoit Tellier <bt...@linagora.com>
Authored: Tue Nov 29 12:02:07 2016 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Tue Jan 10 14:35:32 2017 +0700

----------------------------------------------------------------------
 .../james/transport/mailets/RemoteDelivery.java | 107 +-----------
 .../remoteDelivery/DelaysAndMaxRetry.java       | 166 +++++++++++++++++++
 .../mailets/remoteDelivery/DelayTest.java       |  21 +++
 .../remoteDelivery/DelaysAndMaxRetryTest.java   | 136 +++++++++++++++
 4 files changed, 329 insertions(+), 101 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/8a8af97a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
index b23f79d..9ffd164 100644
--- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/RemoteDelivery.java
@@ -64,6 +64,7 @@ import org.apache.james.queue.api.MailQueue.MailQueueException;
 import org.apache.james.queue.api.MailQueue.MailQueueItem;
 import org.apache.james.queue.api.MailQueueFactory;
 import org.apache.james.transport.mailets.remoteDelivery.Delay;
+import org.apache.james.transport.mailets.remoteDelivery.DelaysAndMaxRetry;
 import org.apache.james.transport.mailets.remoteDelivery.HeloNameProvider;
 import org.apache.james.transport.mailets.remoteDelivery.RemoteDeliverySocketFactory;
 import org.apache.mailet.HostAddress;
@@ -170,7 +171,7 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
     /**
      * Maximum no. of retries (Defaults to 5).
      */
-    private int maxRetries = 5;
+    private int maxRetries;
 
     /**
      * Default number of ms to timeout on smtp delivery
@@ -264,61 +265,11 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
 
         logger = getMailetContext().getLogger();
 
-        // Create list of Delay Times.
-        ArrayList<Delay> delayTimesList = new ArrayList<Delay>();
         try {
-            if (getInitParameter("delayTime") != null) {
-
-                // parses delayTimes specified in config file.
-                String delayTimesParm = getInitParameter("delayTime");
-
-                // Split on commas
-                StringTokenizer st = new StringTokenizer(delayTimesParm, ",");
-                while (st.hasMoreTokens()) {
-                    String delayTime = st.nextToken();
-                    delayTimesList.add(new Delay(delayTime));
-                }
-            } else {
-                // Use default delayTime.
-                delayTimesList.add(new Delay());
-            }
-        } catch (Exception e) {
-            log("Invalid delayTime setting: " + getInitParameter("delayTime"));
-        }
-
-        try {
-            // Get No. of Max Retries.
-            if (getInitParameter("maxRetries") != null) {
-                maxRetries = Integer.parseInt(getInitParameter("maxRetries"));
-            }
-
-            // Check consistency of 'maxRetries' with delayTimesList attempts.
-            int totalAttempts = calcTotalAttempts(delayTimesList);
-
-            // If inconsistency found, fix it.
-            if (totalAttempts > maxRetries) {
-                log("Total number of delayTime attempts exceeds maxRetries specified. " + " Increasing maxRetries from " + maxRetries + " to " + totalAttempts);
-                maxRetries = totalAttempts;
-            } else {
-                int extra = maxRetries - totalAttempts;
-                if (extra != 0) {
-                    log("maxRetries is larger than total number of attempts specified.  " + "Increasing last delayTime with " + extra + " attempts ");
-
-                    // Add extra attempts to the last delayTime.
-                    if (delayTimesList.size() != 0) {
-                        // Get the last delayTime.
-                        Delay delay = delayTimesList.get(delayTimesList.size() - 1);
-
-                        // Increase no. of attempts.
-                        delay.setAttempts(delay.getAttempts() + extra);
-                        log("Delay of " + delay.getDelayTime() + " msecs is now attempted: " + delay.getAttempts() + " times");
-                    } else {
-                        throw new MessagingException("No delaytimes, cannot continue");
-                    }
-                }
-            }
-            delayTimes = expandDelays(delayTimesList);
-
+            int intendedMaxRetries = Integer.parseInt(getInitParameter("maxRetries", "5"));
+            DelaysAndMaxRetry delaysAndMaxRetry = DelaysAndMaxRetry.from(intendedMaxRetries, getInitParameter("delayTime"));
+            maxRetries = delaysAndMaxRetry.getMaxRetries();
+            delayTimes = delaysAndMaxRetry.getExpendedDelays();
         } catch (Exception e) {
             log("Invalid maxRetries setting: " + getInitParameter("maxRetries"));
         }
@@ -435,52 +386,6 @@ public class RemoteDelivery extends GenericMailet implements Runnable {
     }
 
     /**
-     * Calculates Total no. of attempts for the specified delayList.
-     *
-     * @param delayList list of 'Delay' objects
-     * @return total no. of retry attempts
-     */
-    private int calcTotalAttempts(ArrayList<Delay> delayList) {
-        int sum = 0;
-        for (Delay delay : delayList) {
-            sum += delay.getAttempts();
-        }
-        return sum;
-    }
-
-    /**
-     * <p>
-     * This method expands an ArrayList containing Delay objects into an array
-     * holding the only delaytime in the order.
-     * </p>
-     * <p/>
-     * So if the list has 2 Delay objects the first having attempts=2 and
-     * delaytime 4000 the second having attempts=1 and delaytime=300000 will be
-     * expanded into this array:
-     * <p/>
-     * <pre>
-     * long[0] = 4000
-     * long[1] = 4000
-     * long[2] = 300000
-     * </pre>
-     *
-     * @param list the list to expand
-     * @return the expanded list
-     */
-    private long[] expandDelays(ArrayList<Delay> list) {
-        long[] delays = new long[calcTotalAttempts(list)];
-        Iterator<Delay> i = list.iterator();
-        int idx = 0;
-        while (i.hasNext()) {
-            Delay delay = i.next();
-            for (int j = 0; j < delay.getAttempts(); j++) {
-                delays[idx++] = delay.getDelayTime();
-            }
-        }
-        return delays;
-    }
-
-    /**
      * This method returns, given a retry-count, the next delay time to use.
      *
      * @param retry_count the current retry_count.

http://git-wip-us.apache.org/repos/asf/james-project/blob/8a8af97a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetry.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetry.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetry.java
new file mode 100644
index 0000000..10b6cca
--- /dev/null
+++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetry.java
@@ -0,0 +1,166 @@
+/****************************************************************
+ * 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 org.apache.james.transport.mailets.remoteDelivery;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import javax.mail.MessagingException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+
+public class DelaysAndMaxRetry {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(DelaysAndMaxRetry.class);
+
+    public static DelaysAndMaxRetry from(int intendedMaxRetries, String delaysAsString) throws MessagingException {
+        // Create list of Delay Times.
+        ArrayList<Delay> delayTimesList = createDelayList(delaysAsString);
+
+        // Check consistency of 'maxRetries' with delayTimesList attempts.
+        int totalAttempts = calcTotalAttempts(delayTimesList);
+
+        // If inconsistency found, fix it.
+        if (totalAttempts > intendedMaxRetries) {
+            LOGGER.warn("Total number of delayTime attempts exceeds maxRetries specified. " + " Increasing maxRetries from " + intendedMaxRetries + " to " + totalAttempts);
+            return new DelaysAndMaxRetry(totalAttempts, delayTimesList);
+        } else {
+            int extra = intendedMaxRetries - totalAttempts;
+            if (extra != 0) {
+                LOGGER.warn("maxRetries is larger than total number of attempts specified.  " + "Increasing last delayTime with " + extra + " attempts ");
+
+                // Add extra attempts to the last delayTime.
+                if (delayTimesList.size() != 0) {
+                    // Get the last delayTime.
+                    Delay delay = delayTimesList.get(delayTimesList.size() - 1);
+
+                    // Increase no. of attempts.
+                    delay.setAttempts(delay.getAttempts() + extra);
+                    LOGGER.warn("Delay of " + delay.getDelayTime() + " msecs is now attempted: " + delay.getAttempts() + " times");
+                } else {
+                    throw new MessagingException("No delaytimes, cannot continue");
+                }
+            }
+            return new DelaysAndMaxRetry(intendedMaxRetries, delayTimesList);
+        }
+    }
+
+    private static ArrayList<Delay> createDelayList(String delaysAsString) {
+        ArrayList<Delay> delayTimesList = new ArrayList<Delay>();
+        try {
+            if (delaysAsString != null) {
+
+                // Split on commas
+                StringTokenizer st = new StringTokenizer(delaysAsString, ",");
+                while (st.hasMoreTokens()) {
+                    String delayTime = st.nextToken();
+                    delayTimesList.add(new Delay(delayTime));
+                }
+            } else {
+                // Use default delayTime.
+                delayTimesList.add(new Delay());
+            }
+        } catch (Exception e) {
+            LOGGER.warn("Invalid delayTime setting: " + delaysAsString);
+        }
+        return delayTimesList;
+    }
+
+    /**
+     * Calculates Total no. of attempts for the specified delayList.
+     *
+     * @param delayList list of 'Delay' objects
+     * @return total no. of retry attempts
+     */
+    private static int calcTotalAttempts(List<Delay> delayList) {
+        int sum = 0;
+        for (Delay delay : delayList) {
+            sum += delay.getAttempts();
+        }
+        return sum;
+    }
+
+    private final int maxRetries;
+    private final List<Delay> delays;
+
+    @VisibleForTesting
+    DelaysAndMaxRetry(int maxRetries, List<Delay> delays) {
+        this.maxRetries = maxRetries;
+        this.delays = ImmutableList.copyOf(delays);
+    }
+
+    public int getMaxRetries() {
+        return maxRetries;
+    }
+
+    /**
+     * <p>
+     * This method expands an ArrayList containing Delay objects into an array
+     * holding the only delaytime in the order.
+     * </p>
+     * <p/>
+     * So if the list has 2 Delay objects the first having attempts=2 and
+     * delaytime 4000 the second having attempts=1 and delaytime=300000 will be
+     * expanded into this array:
+     * <p/>
+     * <pre>
+     * long[0] = 4000
+     * long[1] = 4000
+     * long[2] = 300000
+     * </pre>
+     *
+     * @param list the list to expand
+     * @return the expanded list
+     */
+    public long[] getExpendedDelays() {
+        long[] delaysAsLong = new long[calcTotalAttempts(delays)];
+        Iterator<Delay> i = delays.iterator();
+        int idx = 0;
+        while (i.hasNext()) {
+            Delay delay = i.next();
+            for (int j = 0; j < delay.getAttempts(); j++) {
+                delaysAsLong[idx++] = delay.getDelayTime();
+            }
+        }
+        return delaysAsLong;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof DelaysAndMaxRetry) {
+            DelaysAndMaxRetry that = (DelaysAndMaxRetry) o;
+            return Objects.equal(this.maxRetries, that.maxRetries)
+                && Objects.equal(this.delays, that.delays);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(maxRetries, delays);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/8a8af97a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java
index 92ce97b..f23c918 100644
--- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelayTest.java
@@ -76,6 +76,20 @@ public class DelayTest {
     }
 
     @Test
+    public void stringConstructorShouldThrowWhenAttemptsOmitted() throws Exception {
+        expectedException.expect(NumberFormatException.class);
+
+        new Delay("*36");
+    }
+
+    @Test
+    public void stringConstructorShouldThrowWhenDelayOmitted() throws Exception {
+        expectedException.expect(MessagingException.class);
+
+        new Delay("2*");
+    }
+
+    @Test
     public void stringConstructorShouldWorkForNumberAttemptsAndUnit() throws Exception {
         assertThat(new Delay("2*36s")).isEqualTo(new Delay(2, 36000));
     }
@@ -93,4 +107,11 @@ public class DelayTest {
 
         new Delay("36invalid");
     }
+
+    @Test
+    public void stringConstructorShouldThrowOnEmptyString() throws Exception {
+        expectedException.expect(MessagingException.class);
+
+        new Delay("");
+    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/8a8af97a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetryTest.java
----------------------------------------------------------------------
diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetryTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetryTest.java
new file mode 100644
index 0000000..da4ecda
--- /dev/null
+++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/remoteDelivery/DelaysAndMaxRetryTest.java
@@ -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 org.apache.james.transport.mailets.remoteDelivery;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import javax.mail.MessagingException;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import com.google.common.collect.ImmutableList;
+
+public class DelaysAndMaxRetryTest {
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Test
+    public void fromShouldParseSingleDelay() throws Exception {
+        DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(1, "1s");
+
+        DelaysAndMaxRetry expected = new DelaysAndMaxRetry(1, ImmutableList.of(new Delay(1, 1000)));
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void fromShouldParseTwoDelays() throws Exception {
+        DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(2, "1s,2s");
+
+        DelaysAndMaxRetry expected = new DelaysAndMaxRetry(2, ImmutableList.of(new Delay(1, 1000), new Delay(1, 2000)));
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void fromShouldAdaptMaxRetriesWhenUnderAttempts() throws Exception {
+        DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(1, "1s,2*2s");
+
+        DelaysAndMaxRetry expected = new DelaysAndMaxRetry(3, ImmutableList.of(new Delay(1, 1000), new Delay(2, 2000)));
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void fromShouldAdaptDelaysWhenUnderMaxRetries() throws Exception {
+        DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(4, "1s,2*2s");
+
+        DelaysAndMaxRetry expected = new DelaysAndMaxRetry(4, ImmutableList.of(new Delay(1, 1000), new Delay(3, 2000)));
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void fromShouldHandleNullValuesForDelayAsString() throws Exception {
+        DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(1, null);
+
+        DelaysAndMaxRetry expected = new DelaysAndMaxRetry(1, ImmutableList.of(new Delay(Delay.DEFAULT_ATTEMPTS, Delay.DEFAULT_DELAY_TIME)));
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void fromShouldIgnoreEmptyDelay() throws Exception {
+        DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(1, "1s,,2s");
+
+        DelaysAndMaxRetry expected = new DelaysAndMaxRetry(2, ImmutableList.of(new Delay(1, 1000), new Delay(1, 2000)));
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void fromShouldHandleParsingFailures() throws Exception {
+        DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(3, "1s,invalid,2s");
+
+        DelaysAndMaxRetry expected = new DelaysAndMaxRetry(3, ImmutableList.of(new Delay(3, 1000)));
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void fromShouldHandleEmptyStringWithZeroMaxRetries() throws Exception {
+        DelaysAndMaxRetry actual = DelaysAndMaxRetry.from(0, "");
+
+        DelaysAndMaxRetry expected = new DelaysAndMaxRetry(0, ImmutableList.<Delay>of());
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void fromShouldThrowOnEmptyStringWithNonZeroMaxRetry() throws Exception {
+        expectedException.expect(MessagingException.class);
+
+        DelaysAndMaxRetry.from(2, "");
+    }
+
+    @Test
+    public void getExpendedDelaysShouldReturnEmptyWhenNoDelay() throws Exception {
+        DelaysAndMaxRetry testee = DelaysAndMaxRetry.from(0, "");
+
+        assertThat(testee.getExpendedDelays()).isEmpty();
+    }
+
+    @Test
+    public void getExpendedDelaysShouldExpandSingleDelays() throws Exception {
+        DelaysAndMaxRetry testee = DelaysAndMaxRetry.from(3, "1*1S,1*2S,1*5S");
+
+        assertThat(testee.getExpendedDelays()).containsExactly(1000, 2000, 5000);
+    }
+
+    @Test
+    public void getExpendedDelaysShouldExpandMultipleDelays() throws Exception {
+        DelaysAndMaxRetry testee = DelaysAndMaxRetry.from(3, "1*1S,2*2S,2*5S");
+
+        assertThat(testee.getExpendedDelays()).containsExactly(1000, 2000, 2000, 5000, 5000);
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org