27
27
/**
28
28
* A Failsafe wrapped Retrofit {@link Call}. Supports synchronous and asynchronous executions, and cancellation.
29
29
*
30
- * @param <T > response type
30
+ * @param <R > response type
31
31
* @author Jonathan Halterman
32
32
*/
33
- public final class FailsafeCall <T > {
34
- private final FailsafeExecutor <Response <T >> failsafe ;
35
- private final retrofit2 .Call <T > initialCall ;
33
+ public final class FailsafeCall <R > {
34
+ private final FailsafeExecutor <Response <R >> failsafe ;
35
+ private final retrofit2 .Call <R > initialCall ;
36
36
37
- private volatile Call <Response <T >> failsafeCall ;
38
- private volatile CompletableFuture <Response <T >> failsafeFuture ;
37
+ private volatile Call <Response <R >> failsafeCall ;
38
+ private volatile CompletableFuture <Response <R >> failsafeFuture ;
39
39
private AtomicBoolean cancelled = new AtomicBoolean ();
40
40
private AtomicBoolean executed = new AtomicBoolean ();
41
41
42
- private FailsafeCall (retrofit2 .Call <T > call , FailsafeExecutor <Response <T >> failsafe ) {
43
- this .initialCall = call ;
42
+ private FailsafeCall (FailsafeExecutor <Response <R >> failsafe , retrofit2 .Call <R > call ) {
44
43
this .failsafe = failsafe ;
44
+ this .initialCall = call ;
45
+ }
46
+
47
+ public static final class FailsafeCallBuilder <R > {
48
+ private FailsafeExecutor <Response <R >> failsafe ;
49
+
50
+ private FailsafeCallBuilder (FailsafeExecutor <Response <R >> failsafe ) {
51
+ this .failsafe = failsafe ;
52
+ }
53
+
54
+ public <P extends Policy <Response <R >>> FailsafeCallBuilder <R > compose (P innerPolicy ) {
55
+ failsafe = failsafe .compose (innerPolicy );
56
+ return this ;
57
+ }
58
+
59
+ public FailsafeCall <R > compose (retrofit2 .Call <R > call ) {
60
+ return new FailsafeCall <>(failsafe , call );
61
+ }
45
62
}
46
63
47
64
/**
48
- * Returns a FailsafeCall for the {@code call}, {@code outerPolicy} and {@code policies}. See {@link
49
- * Failsafe#with(Policy, Policy[])} for docs on how policy composition works.
65
+ * Returns a FailsafeCallBuilder for the {@code outerPolicy} and {@code policies}. See {@link Failsafe#with(Policy,
66
+ * Policy[])} for docs on how policy composition works.
50
67
*
51
- * @param <T> response type
68
+ * @param <R> result type
52
69
* @param <P> policy type
53
70
* @throws NullPointerException if {@code call} or {@code outerPolicy} are null
54
71
*/
55
72
@ SafeVarargs
56
- public static <T , P extends Policy <Response <T >>> FailsafeCall <T > of (retrofit2 .Call <T > call , P outerPolicy ,
57
- P ... policies ) {
58
- return of (call , Failsafe .with (outerPolicy , policies ));
73
+ public static <R , P extends Policy <Response <R >>> FailsafeCallBuilder <R > with (P outerPolicy , P ... policies ) {
74
+ return new FailsafeCallBuilder <>(Failsafe .with (outerPolicy , policies ));
59
75
}
60
76
61
77
/**
62
- * Returns a FailsafeCall for the {@code call} and {@code failsafeExecutor}.
78
+ * Returns a FailsafeCallBuilder for the {@code failsafeExecutor}.
63
79
*
64
- * @param <T> response type
65
- * @throws NullPointerException if {@code call} or {@code failsafeExecutor} are null
80
+ * @param <R> result type
81
+ * @throws NullPointerException if {@code failsafeExecutor} is null
66
82
*/
67
- public static <T > FailsafeCall < T > of ( retrofit2 . Call < T > call , FailsafeExecutor <Response <T >> failsafeExecutor ) {
68
- return new FailsafeCall <>(Assert . notNull ( call , "call" ), Assert .notNull (failsafeExecutor , "failsafeExecutor" ));
83
+ public static <R > FailsafeCallBuilder < R > with ( FailsafeExecutor <Response <R >> failsafeExecutor ) {
84
+ return new FailsafeCallBuilder <>(Assert .notNull (failsafeExecutor , "failsafeExecutor" ));
69
85
}
70
86
71
87
/**
@@ -83,8 +99,8 @@ public void cancel() {
83
99
/**
84
100
* Returns a clone of the FailsafeCall.
85
101
*/
86
- public FailsafeCall <T > clone () {
87
- return FailsafeCall . of ( initialCall .clone (), failsafe );
102
+ public FailsafeCall <R > clone () {
103
+ return new FailsafeCall <>( failsafe , initialCall .clone ());
88
104
}
89
105
90
106
/**
@@ -95,7 +111,7 @@ public FailsafeCall<T> clone() {
95
111
* @throws FailsafeException if the execution fails with a checked Exception. {@link FailsafeException#getCause()} can
96
112
* be used to learn the underlying checked exception.
97
113
*/
98
- public Response <T > execute () throws IOException {
114
+ public Response <R > execute () throws IOException {
99
115
Assert .isTrue (executed .compareAndSet (false , true ), "already executed" );
100
116
101
117
failsafeCall = failsafe .newCall (ctx -> {
@@ -114,22 +130,22 @@ public Response<T> execute() throws IOException {
114
130
/**
115
131
* Executes the call asynchronously until a successful result is returned or the configured policies are exceeded.
116
132
*/
117
- public CompletableFuture <Response <T >> executeAsync () {
133
+ public CompletableFuture <Response <R >> executeAsync () {
118
134
if (!executed .compareAndSet (false , true )) {
119
- CompletableFuture <Response <T >> result = new CompletableFuture <>();
135
+ CompletableFuture <Response <R >> result = new CompletableFuture <>();
120
136
result .completeExceptionally (new IllegalStateException ("already executed" ));
121
137
return result ;
122
138
}
123
139
124
140
failsafeFuture = failsafe .getAsyncExecution (exec -> {
125
- prepareCall (exec ).enqueue (new Callback <T >() {
141
+ prepareCall (exec ).enqueue (new Callback <R >() {
126
142
@ Override
127
- public void onResponse (retrofit2 .Call <T > call , Response <T > response ) {
143
+ public void onResponse (retrofit2 .Call <R > call , Response <R > response ) {
128
144
exec .recordResult (response );
129
145
}
130
146
131
147
@ Override
132
- public void onFailure (retrofit2 .Call <T > call , Throwable throwable ) {
148
+ public void onFailure (retrofit2 .Call <R > call , Throwable throwable ) {
133
149
exec .recordException (throwable );
134
150
}
135
151
});
@@ -152,8 +168,8 @@ public boolean isExecuted() {
152
168
return executed .get ();
153
169
}
154
170
155
- private retrofit2 .Call <T > prepareCall (ExecutionContext <Response <T >> ctx ) {
156
- retrofit2 .Call <T > call = ctx .isFirstAttempt () ? initialCall : initialCall .clone ();
171
+ private retrofit2 .Call <R > prepareCall (ExecutionContext <Response <R >> ctx ) {
172
+ retrofit2 .Call <R > call = ctx .isFirstAttempt () ? initialCall : initialCall .clone ();
157
173
158
174
// Propagate cancellation to the call
159
175
ctx .onCancel (() -> {
0 commit comments