1 /*
2 Copyright 2010 Atlassian
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16 package io.atlassian.fugue.retry;
17
18 import io.atlassian.fugue.Suppliers;
19
20 import java.util.function.Function;
21
22 import static java.util.Objects.requireNonNull;
23
24 /**
25 * A Function which wraps the apply method of another Function and attempts it
26 * up to a fixed number of times. This class can be used when a task is known to
27 * be prone to occasional failure and other workarounds are not known.
28 *
29 * @param <F> The type of the parameter the Function accepts
30 * @param <T> The type of the result the Function yields upon application
31 * @see RetrySupplier for a Supplier implementation
32 * @see RetryTask for a Runnable implementation
33 * @see RetryFactory for some factory methods
34 */
35 public class RetryFunction<F, T> implements Function<F, T> {
36 private final Function<F, T> function;
37 private final int tries;
38 private final ExceptionHandler handler;
39 private final Runnable beforeRetry;
40
41 /**
42 * An instance that does nothing before retrying and ignores exceptions that
43 * occur.
44 *
45 * @param function which fetches the result, must not be null
46 * @param tries the numbe rof times to attempt to get a result, must be
47 * positive
48 */
49 public RetryFunction(Function<F, T> function, int tries) {
50 this(function, tries, ExceptionHandlers.ignoreExceptionHandler());
51 }
52
53 /**
54 * An instance that does nothing before retrying.
55 *
56 * @param function which fetches the result, must not be null
57 * @param tries the number of times to attempt to get a result, must be
58 * positive
59 * @param handler reacts to exceptions thrown by the supplier, must not be
60 * null
61 */
62 public RetryFunction(Function<F, T> function, int tries, ExceptionHandler handler) {
63 this(function, tries, handler, new NoOp());
64 }
65
66 /**
67 * <p>
68 * Constructor for RetryFunction.
69 * </p>
70 *
71 * @param function which fetches the result, must not be null
72 * @param tries the number of times to attempt to get a result, must be
73 * positive
74 * @param handler reacts to exceptions thrown by the supplier, must not be
75 * null
76 * @param beforeRetry an effect that is run before a retry attempt
77 */
78 public RetryFunction(Function<F, T> function, int tries, ExceptionHandler handler, Runnable beforeRetry) {
79
80 this.function = requireNonNull(function);
81 this.handler = requireNonNull(handler);
82 if (tries < 0) {
83 throw new IllegalArgumentException("Tries must not be negative");
84 }
85 this.tries = tries;
86 this.beforeRetry = requireNonNull(beforeRetry);
87 }
88
89 /**
90 * {@inheritDoc}
91 *
92 * Attempt to apply <i>parameter</i> to the wrapped Function <i>tries</i>
93 * number of times. Any exceptions thrown will be ignored until the number of
94 * attempts is reached. If the number of attempts is reached without a
95 * successful result, the most recent exception to be thrown will be rethrown.
96 */
97 @Override public T apply(F parameter) {
98 return new RetrySupplier<>(Suppliers.compose(function, Suppliers.ofInstance(parameter)), tries, handler, beforeRetry).get();
99 }
100 }