26
26
import com .google .common .base .Supplier ;
27
27
import com .google .common .base .Suppliers ;
28
28
import com .google .common .collect .ImmutableList ;
29
+ import com .google .common .util .concurrent .MoreExecutors ;
29
30
import com .google .firebase .ErrorCode ;
30
31
import com .google .firebase .FirebaseApp ;
31
32
import com .google .firebase .ImplFirebaseTrampolines ;
@@ -159,7 +160,7 @@ protected String execute() throws FirebaseMessagingException {
159
160
* no failures are only indicated by a {@link BatchResponse}.
160
161
*/
161
162
public BatchResponse sendEach (@ NonNull List <Message > messages ) throws FirebaseMessagingException {
162
- return sendEachOp (messages , false ). call ( );
163
+ return sendEach (messages , false );
163
164
}
164
165
165
166
@@ -186,7 +187,11 @@ public BatchResponse sendEach(@NonNull List<Message> messages) throws FirebaseMe
186
187
*/
187
188
public BatchResponse sendEach (
188
189
@ NonNull List <Message > messages , boolean dryRun ) throws FirebaseMessagingException {
189
- return sendEachOp (messages , dryRun ).call ();
190
+ try {
191
+ return sendEachOpAsync (messages , dryRun ).get ();
192
+ } catch (InterruptedException | ExecutionException e ) {
193
+ throw new FirebaseMessagingException (ErrorCode .CANCELLED , SERVICE_ID );
194
+ }
190
195
}
191
196
192
197
/**
@@ -197,7 +202,7 @@ public BatchResponse sendEach(
197
202
* the messages have been sent.
198
203
*/
199
204
public ApiFuture <BatchResponse > sendEachAsync (@ NonNull List <Message > messages ) {
200
- return sendEachOp (messages , false ). callAsync ( app );
205
+ return sendEachOpAsync (messages , false );
201
206
}
202
207
203
208
/**
@@ -209,32 +214,37 @@ public ApiFuture<BatchResponse> sendEachAsync(@NonNull List<Message> messages) {
209
214
* the messages have been sent.
210
215
*/
211
216
public ApiFuture <BatchResponse > sendEachAsync (@ NonNull List <Message > messages , boolean dryRun ) {
212
- return sendEachOp (messages , dryRun ). callAsync ( app );
217
+ return sendEachOpAsync (messages , dryRun );
213
218
}
214
219
215
- private CallableOperation <BatchResponse , FirebaseMessagingException > sendEachOp (
220
+ // Returns an ApiFuture directly since this function is non-blocking. Individual child send
221
+ // requests are still called async and run in background threads.
222
+ private ApiFuture <BatchResponse > sendEachOpAsync (
216
223
final List <Message > messages , final boolean dryRun ) {
217
224
final List <Message > immutableMessages = ImmutableList .copyOf (messages );
218
225
checkArgument (!immutableMessages .isEmpty (), "messages list must not be empty" );
219
226
checkArgument (immutableMessages .size () <= 500 ,
220
227
"messages list must not contain more than 500 elements" );
221
228
222
- return new CallableOperation <BatchResponse , FirebaseMessagingException >() {
223
- @ Override
224
- protected BatchResponse execute () throws FirebaseMessagingException {
225
- List <ApiFuture <SendResponse >> list = new ArrayList <>();
226
- for (Message message : immutableMessages ) {
227
- ApiFuture <SendResponse > messageId = sendOpForSendResponse (message , dryRun ).callAsync (app );
228
- list .add (messageId );
229
- }
230
- try {
231
- List <SendResponse > responses = ApiFutures .allAsList (list ).get ();
232
- return new BatchResponseImpl (responses );
233
- } catch (InterruptedException | ExecutionException e ) {
234
- throw new FirebaseMessagingException (ErrorCode .CANCELLED , SERVICE_ID );
235
- }
236
- }
237
- };
229
+ List <ApiFuture <SendResponse >> list = new ArrayList <>();
230
+ for (Message message : immutableMessages ) {
231
+ // Make async send calls per message
232
+ ApiFuture <SendResponse > messageId = sendOpForSendResponse (message , dryRun ).callAsync (app );
233
+ list .add (messageId );
234
+ }
235
+
236
+ // Gather all futures and combine into a list
237
+ ApiFuture <List <SendResponse >> responsesFuture = ApiFutures .allAsList (list );
238
+
239
+ // Chain this future to wrap the eventual responses in a BatchResponse without blocking
240
+ // the main thread. This uses the current thread to execute, but since the transformation
241
+ // function is non-blocking the transformation itself is also non-blocking.
242
+ return ApiFutures .transform (
243
+ responsesFuture ,
244
+ (responses ) -> {
245
+ return new BatchResponseImpl (responses );
246
+ },
247
+ MoreExecutors .directExecutor ());
238
248
}
239
249
240
250
private CallableOperation <SendResponse , FirebaseMessagingException > sendOpForSendResponse (
0 commit comments