20
20
import static com .google .common .base .Preconditions .checkNotNull ;
21
21
22
22
import com .google .api .core .ApiFuture ;
23
+ import com .google .api .core .ApiFutures ;
23
24
import com .google .common .annotations .VisibleForTesting ;
24
25
import com .google .common .base .Strings ;
25
26
import com .google .common .base .Supplier ;
26
27
import com .google .common .base .Suppliers ;
27
28
import com .google .common .collect .ImmutableList ;
29
+ import com .google .firebase .ErrorCode ;
28
30
import com .google .firebase .FirebaseApp ;
29
31
import com .google .firebase .ImplFirebaseTrampolines ;
30
32
import com .google .firebase .internal .CallableOperation ;
31
33
import com .google .firebase .internal .FirebaseService ;
32
34
import com .google .firebase .internal .NonNull ;
33
35
36
+ import java .util .ArrayList ;
34
37
import java .util .List ;
38
+ import java .util .concurrent .ExecutionException ;
35
39
36
40
/**
37
41
* This class is the entry point for all server-side Firebase Cloud Messaging actions.
@@ -91,7 +95,7 @@ public String send(@NonNull Message message) throws FirebaseMessagingException {
91
95
*
92
96
* <p>If the {@code dryRun} option is set to true, the message will not be actually sent. Instead
93
97
* FCM performs all the necessary validations and emulates the send operation. The {@code dryRun}
94
- * option is useful for determining whether an FCM registration has been deleted. However, it
98
+ * option is useful for determining whether an FCM registration has been deleted. However, it
95
99
* cannot be used to validate APNs tokens.
96
100
*
97
101
* @param message A non-null {@link Message} to be sent.
@@ -139,6 +143,191 @@ protected String execute() throws FirebaseMessagingException {
139
143
};
140
144
}
141
145
146
+ /**
147
+ * Sends each message in the given list via Firebase Cloud Messaging.
148
+ * Unlike {@link #sendAll(List)}, this method makes a single HTTP call for each message in the
149
+ * given array.
150
+ *
151
+ * <p>The responses list obtained by calling {@link BatchResponse#getResponses()} on the return
152
+ * value corresponds to the order of input messages.
153
+ *
154
+ * @param messages A non-null, non-empty list containing up to 500 messages.
155
+ * @return A {@link BatchResponse} indicating the result of the operation.
156
+ * @throws FirebaseMessagingException If an error occurs while handing the messages off to FCM for
157
+ * delivery. An exception here or a {@link BatchResponse} with all failures indicates a total
158
+ * failure -- i.e. none of the messages in the list could be sent. Partial failures or no
159
+ * failures are only indicated by a {@link BatchResponse}.
160
+ */
161
+ public BatchResponse sendEach (@ NonNull List <Message > messages ) throws FirebaseMessagingException {
162
+ return sendEachOp (messages , false ).call ();
163
+ }
164
+
165
+
166
+ /**
167
+ * Sends each message in the given list via Firebase Cloud Messaging.
168
+ * Unlike {@link #sendAll(List)}, this method makes a single HTTP call for each message in the
169
+ * given array.
170
+ *
171
+ * <p>If the {@code dryRun} option is set to true, the message will not be actually sent. Instead
172
+ * FCM performs all the necessary validations, and emulates the send operation. The {@code dryRun}
173
+ * option is useful for determining whether an FCM registration has been deleted. But it cannot be
174
+ * used to validate APNs tokens.
175
+ *
176
+ * <p>The responses list obtained by calling {@link BatchResponse#getResponses()} on the return
177
+ * value corresponds to the order of input messages.
178
+ *
179
+ * @param messages A non-null, non-empty list containing up to 500 messages.
180
+ * @param dryRun A boolean indicating whether to perform a dry run (validation only) of the send.
181
+ * @return A {@link BatchResponse} indicating the result of the operation.
182
+ * @throws FirebaseMessagingException If an error occurs while handing the messages off to FCM for
183
+ * delivery. An exception here or a {@link BatchResponse} with all failures indicates a total
184
+ * failure -- i.e. none of the messages in the list could be sent. Partial failures or no
185
+ * failures are only indicated by a {@link BatchResponse}.
186
+ */
187
+ public BatchResponse sendEach (
188
+ @ NonNull List <Message > messages , boolean dryRun ) throws FirebaseMessagingException {
189
+ return sendEachOp (messages , dryRun ).call ();
190
+ }
191
+
192
+ /**
193
+ * Similar to {@link #sendEach(List)} but performs the operation asynchronously.
194
+ *
195
+ * @param messages A non-null, non-empty list containing up to 500 messages.
196
+ * @return An {@code ApiFuture} that will complete with a {@link BatchResponse} when
197
+ * the messages have been sent.
198
+ */
199
+ public ApiFuture <BatchResponse > sendEachAsync (@ NonNull List <Message > messages ) {
200
+ return sendEachOp (messages , false ).callAsync (app );
201
+ }
202
+
203
+ /**
204
+ * Similar to {@link #sendEach(List, boolean)} but performs the operation asynchronously.
205
+ *
206
+ * @param messages A non-null, non-empty list containing up to 500 messages.
207
+ * @param dryRun A boolean indicating whether to perform a dry run (validation only) of the send.
208
+ * @return An {@code ApiFuture} that will complete with a {@link BatchResponse} when
209
+ * the messages have been sent.
210
+ */
211
+ public ApiFuture <BatchResponse > sendEachAsync (@ NonNull List <Message > messages , boolean dryRun ) {
212
+ return sendEachOp (messages , dryRun ).callAsync (app );
213
+ }
214
+
215
+ private CallableOperation <BatchResponse , FirebaseMessagingException > sendEachOp (
216
+ final List <Message > messages , final boolean dryRun ) {
217
+ final List <Message > immutableMessages = ImmutableList .copyOf (messages );
218
+ checkArgument (!immutableMessages .isEmpty (), "messages list must not be empty" );
219
+ checkArgument (immutableMessages .size () <= 500 ,
220
+ "messages list must not contain more than 500 elements" );
221
+
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
+ };
238
+ }
239
+
240
+ private CallableOperation <SendResponse , FirebaseMessagingException > sendOpForSendResponse (
241
+ final Message message , final boolean dryRun ) {
242
+ checkNotNull (message , "message must not be null" );
243
+ final FirebaseMessagingClient messagingClient = getMessagingClient ();
244
+ return new CallableOperation <SendResponse , FirebaseMessagingException >() {
245
+ @ Override
246
+ protected SendResponse execute () {
247
+ try {
248
+ String messageId = messagingClient .send (message , dryRun );
249
+ return SendResponse .fromMessageId (messageId );
250
+ } catch (FirebaseMessagingException e ) {
251
+ return SendResponse .fromException (e );
252
+ }
253
+ }
254
+ };
255
+ }
256
+
257
+ /**
258
+ * Sends the given multicast message to all the FCM registration tokens specified in it.
259
+ *
260
+ * <p>This method uses the {@link #sendEach(List)} API under the hood to send the given
261
+ * message to all the target recipients. The responses list obtained by calling
262
+ * {@link BatchResponse#getResponses()} on the return value corresponds to the order of tokens
263
+ * in the {@link MulticastMessage}.
264
+ *
265
+ * @param message A non-null {@link MulticastMessage}
266
+ * @return A {@link BatchResponse} indicating the result of the operation.
267
+ * @throws FirebaseMessagingException If an error occurs while handing the messages off to FCM for
268
+ * delivery. An exception here or a {@link BatchResponse} with all failures indicates a total
269
+ * failure -- i.e. none of the messages in the list could be sent. Partial failures or no
270
+ * failures are only indicated by a {@link BatchResponse}.
271
+ */
272
+ public BatchResponse sendEachForMulticast (
273
+ @ NonNull MulticastMessage message ) throws FirebaseMessagingException {
274
+ return sendEachForMulticast (message , false );
275
+ }
276
+
277
+ /**
278
+ * Sends the given multicast message to all the FCM registration tokens specified in it.
279
+ *
280
+ * <p>If the {@code dryRun} option is set to true, the message will not be actually sent. Instead
281
+ * FCM performs all the necessary validations, and emulates the send operation. The {@code dryRun}
282
+ * option is useful for determining whether an FCM registration has been deleted. But it cannot be
283
+ * used to validate APNs tokens.
284
+ *
285
+ * <p>This method uses the {@link #sendEach(List)} API under the hood to send the given
286
+ * message to all the target recipients. The responses list obtained by calling
287
+ * {@link BatchResponse#getResponses()} on the return value corresponds to the order of tokens
288
+ * in the {@link MulticastMessage}.
289
+ *
290
+ * @param message A non-null {@link MulticastMessage}.
291
+ * @param dryRun A boolean indicating whether to perform a dry run (validation only) of the send.
292
+ * @return A {@link BatchResponse} indicating the result of the operation.
293
+ * @throws FirebaseMessagingException If an error occurs while handing the messages off to FCM for
294
+ * delivery. An exception here or a {@link BatchResponse} with all failures indicates a total
295
+ * failure -- i.e. none of the messages in the list could be sent. Partial failures or no
296
+ * failures are only indicated by a {@link BatchResponse}.
297
+ */
298
+ public BatchResponse sendEachForMulticast (@ NonNull MulticastMessage message , boolean dryRun )
299
+ throws FirebaseMessagingException {
300
+ checkNotNull (message , "multicast message must not be null" );
301
+ return sendEach (message .getMessageList (), dryRun );
302
+ }
303
+
304
+ /**
305
+ * Similar to {@link #sendEachForMulticast(MulticastMessage)} but performs the operation
306
+ * asynchronously.
307
+ *
308
+ * @param message A non-null {@link MulticastMessage}.
309
+ * @return An {@code ApiFuture} that will complete with a {@link BatchResponse} when
310
+ * the messages have been sent.
311
+ */
312
+ public ApiFuture <BatchResponse > sendEachForMulticastAsync (@ NonNull MulticastMessage message ) {
313
+ return sendEachForMulticastAsync (message , false );
314
+ }
315
+
316
+ /**
317
+ * Similar to {@link #sendEachForMulticast(MulticastMessage, boolean)} but performs the operation
318
+ * asynchronously.
319
+ *
320
+ * @param message A non-null {@link MulticastMessage}.
321
+ * @param dryRun A boolean indicating whether to perform a dry run (validation only) of the send.
322
+ * @return An {@code ApiFuture} that will complete with a {@link BatchResponse} when
323
+ * the messages have been sent.
324
+ */
325
+ public ApiFuture <BatchResponse > sendEachForMulticastAsync (
326
+ @ NonNull MulticastMessage message , boolean dryRun ) {
327
+ checkNotNull (message , "multicast message must not be null" );
328
+ return sendEachAsync (message .getMessageList (), dryRun );
329
+ }
330
+
142
331
/**
143
332
* Sends all the messages in the given list via Firebase Cloud Messaging. Employs batching to
144
333
* send the entire list as a single RPC call. Compared to the {@link #send(Message)} method, this
@@ -187,7 +376,7 @@ public BatchResponse sendAll(
187
376
* Similar to {@link #sendAll(List)} but performs the operation asynchronously.
188
377
*
189
378
* @param messages A non-null, non-empty list containing up to 500 messages.
190
- * @return @return An {@code ApiFuture} that will complete with a {@link BatchResponse} when
379
+ * @return An {@code ApiFuture} that will complete with a {@link BatchResponse} when
191
380
* the messages have been sent.
192
381
*/
193
382
public ApiFuture <BatchResponse > sendAllAsync (@ NonNull List <Message > messages ) {
@@ -199,7 +388,7 @@ public ApiFuture<BatchResponse> sendAllAsync(@NonNull List<Message> messages) {
199
388
*
200
389
* @param messages A non-null, non-empty list containing up to 500 messages.
201
390
* @param dryRun A boolean indicating whether to perform a dry run (validation only) of the send.
202
- * @return @return An {@code ApiFuture} that will complete with a {@link BatchResponse} when
391
+ * @return An {@code ApiFuture} that will complete with a {@link BatchResponse} when
203
392
* the messages have been sent, or when the emulation has finished.
204
393
*/
205
394
public ApiFuture <BatchResponse > sendAllAsync (
0 commit comments