diff --git a/service/pom.xml b/service/pom.xml index 695c10a27..2799d82b0 100644 --- a/service/pom.xml +++ b/service/pom.xml @@ -114,7 +114,7 @@ com.eatthepath pushy - 0.13.11 + 0.14.1 com.eatthepath diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/push/APNSender.java b/service/src/main/java/org/whispersystems/textsecuregcm/push/APNSender.java index 4cbdff178..faae2a6d6 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/push/APNSender.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/push/APNSender.java @@ -37,7 +37,7 @@ import javax.annotation.Nullable; import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; -import java.util.Date; +import java.time.Instant; import java.util.Optional; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -92,7 +92,7 @@ public class APNSender implements Managed { ListenableFuture future = apnsClient.send(message.getApnId(), topic, message.getMessage(), - new Date(message.getExpirationTime())); + Instant.ofEpochMilli(message.getExpirationTime())); Futures.addCallback(future, new FutureCallback() { @Override diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/push/RetryingApnsClient.java b/service/src/main/java/org/whispersystems/textsecuregcm/push/RetryingApnsClient.java index fa65588f9..706e43ca7 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/push/RetryingApnsClient.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/push/RetryingApnsClient.java @@ -13,7 +13,6 @@ import com.eatthepath.pushy.apns.util.SimpleApnsPushNotification; import com.google.common.annotations.VisibleForTesting; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; -import io.netty.util.concurrent.GenericFutureListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.whispersystems.textsecuregcm.util.Constants; @@ -22,9 +21,9 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; -import java.util.Date; +import java.time.Instant; import java.util.Map; -import java.util.concurrent.ExecutionException; +import java.util.function.BiConsumer; import static com.codahale.metrics.MetricRegistry.name; @@ -55,11 +54,11 @@ public class RetryingApnsClient { this.apnsClient = apnsClient; } - ListenableFuture send(final String apnId, final String topic, final String payload, final Date expiration) { + ListenableFuture send(final String apnId, final String topic, final String payload, final Instant expiration) { SettableFuture result = SettableFuture.create(); SimpleApnsPushNotification notification = new SimpleApnsPushNotification(apnId, topic, payload, expiration, DeliveryPriority.IMMEDIATE); - apnsClient.sendNotification(notification).addListener(new ResponseHandler(result)); + apnsClient.sendNotification(notification).whenComplete(new ResponseHandler(result)); return result; } @@ -68,7 +67,7 @@ public class RetryingApnsClient { apnsClient.close(); } - private static final class ResponseHandler implements GenericFutureListener>> { + private static final class ResponseHandler implements BiConsumer, Throwable> { private final SettableFuture future; @@ -77,27 +76,20 @@ public class RetryingApnsClient { } @Override - public void operationComplete(io.netty.util.concurrent.Future> result) { - try { - PushNotificationResponse response = result.get(); - + public void accept(final PushNotificationResponse response, final Throwable cause) { + if (response != null) { if (response.isAccepted()) { future.set(new ApnResult(ApnResult.Status.SUCCESS, null)); } else if ("Unregistered".equals(response.getRejectionReason()) || - "BadDeviceToken".equals(response.getRejectionReason())) - { + "BadDeviceToken".equals(response.getRejectionReason())) { future.set(new ApnResult(ApnResult.Status.NO_SUCH_USER, response.getRejectionReason())); } else { logger.warn("Got APN failure: " + response.getRejectionReason()); future.set(new ApnResult(ApnResult.Status.GENERIC_FAILURE, response.getRejectionReason())); } - - } catch (InterruptedException e) { - logger.warn("Interrupted exception", e); - future.setException(e); - } catch (ExecutionException e) { - logger.warn("Execution exception", e); - future.setException(e.getCause()); + } else { + logger.warn("Execution exception", cause); + future.setException(cause); } } } diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/push/APNSenderTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/push/APNSenderTest.java index 47c2f4383..7d3672af7 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/push/APNSenderTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/push/APNSenderTest.java @@ -21,14 +21,13 @@ import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.tests.util.SynchronousExecutorService; -import java.util.Date; +import java.time.Instant; import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import io.netty.util.concurrent.DefaultEventExecutor; -import io.netty.util.concurrent.DefaultPromise; -import io.netty.util.concurrent.EventExecutor; + import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.*; @@ -43,8 +42,6 @@ public class APNSenderTest { private final Device destinationDevice = mock(Device.class); private final ApnFallbackManager fallbackManager = mock(ApnFallbackManager.class); - private final DefaultEventExecutor executor = new DefaultEventExecutor(); - @Before public void setup() { when(destinationAccount.getDevice(1)).thenReturn(Optional.of(destinationDevice)); @@ -60,7 +57,7 @@ public class APNSenderTest { when(response.isAccepted()).thenReturn(true); when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class))) - .thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(executor, invocationOnMock.getArgument(0), response)); + .thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response)); RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient); ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_NUMBER, 1, true, Optional.empty()); @@ -74,7 +71,7 @@ public class APNSenderTest { verify(apnsClient, times(1)).sendNotification(notification.capture()); assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID); - assertThat(notification.getValue().getExpiration()).isEqualTo(new Date(ApnMessage.MAX_EXPIRATION)); + assertThat(notification.getValue().getExpiration()).isEqualTo(Instant.ofEpochMilli(ApnMessage.MAX_EXPIRATION)); assertThat(notification.getValue().getPayload()).isEqualTo(ApnMessage.APN_NOTIFICATION_PAYLOAD); assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE); assertThat(notification.getValue().getTopic()).isEqualTo("foo.voip"); @@ -94,7 +91,7 @@ public class APNSenderTest { when(response.isAccepted()).thenReturn(true); when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class))) - .thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(executor, invocationOnMock.getArgument(0), response)); + .thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response)); RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient); ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_NUMBER, 1, false, Optional.empty()); @@ -108,7 +105,7 @@ public class APNSenderTest { verify(apnsClient, times(1)).sendNotification(notification.capture()); assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID); - assertThat(notification.getValue().getExpiration()).isEqualTo(new Date(ApnMessage.MAX_EXPIRATION)); + assertThat(notification.getValue().getExpiration()).isEqualTo(Instant.ofEpochMilli(ApnMessage.MAX_EXPIRATION)); assertThat(notification.getValue().getPayload()).isEqualTo(ApnMessage.APN_NOTIFICATION_PAYLOAD); assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE); assertThat(notification.getValue().getTopic()).isEqualTo("foo"); @@ -129,7 +126,7 @@ public class APNSenderTest { when(response.getRejectionReason()).thenReturn("Unregistered"); when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class))) - .thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(executor, invocationOnMock.getArgument(0), response)); + .thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response)); RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient); @@ -149,7 +146,7 @@ public class APNSenderTest { verify(apnsClient, times(1)).sendNotification(notification.capture()); assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID); - assertThat(notification.getValue().getExpiration()).isEqualTo(new Date(ApnMessage.MAX_EXPIRATION)); + assertThat(notification.getValue().getExpiration()).isEqualTo(Instant.ofEpochMilli(ApnMessage.MAX_EXPIRATION)); assertThat(notification.getValue().getPayload()).isEqualTo(ApnMessage.APN_NOTIFICATION_PAYLOAD); assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE); @@ -233,7 +230,7 @@ public class APNSenderTest { when(response.getRejectionReason()).thenReturn("Unregistered"); when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class))) - .thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(executor, invocationOnMock.getArgument(0), response)); + .thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response)); RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient); ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_NUMBER, 1, true, Optional.empty()); @@ -252,7 +249,7 @@ public class APNSenderTest { verify(apnsClient, times(1)).sendNotification(notification.capture()); assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID); - assertThat(notification.getValue().getExpiration()).isEqualTo(new Date(ApnMessage.MAX_EXPIRATION)); + assertThat(notification.getValue().getExpiration()).isEqualTo(Instant.ofEpochMilli(ApnMessage.MAX_EXPIRATION)); assertThat(notification.getValue().getPayload()).isEqualTo(ApnMessage.APN_NOTIFICATION_PAYLOAD); assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE); @@ -328,7 +325,7 @@ public class APNSenderTest { when(response.getRejectionReason()).thenReturn("BadTopic"); when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class))) - .thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(executor, invocationOnMock.getArgument(0), response)); + .thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), response)); RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient); ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_NUMBER, 1, true, Optional.empty()); @@ -342,7 +339,7 @@ public class APNSenderTest { verify(apnsClient, times(1)).sendNotification(notification.capture()); assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID); - assertThat(notification.getValue().getExpiration()).isEqualTo(new Date(ApnMessage.MAX_EXPIRATION)); + assertThat(notification.getValue().getExpiration()).isEqualTo(Instant.ofEpochMilli(ApnMessage.MAX_EXPIRATION)); assertThat(notification.getValue().getPayload()).isEqualTo(ApnMessage.APN_NOTIFICATION_PAYLOAD); assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE); @@ -361,7 +358,7 @@ public class APNSenderTest { when(response.isAccepted()).thenReturn(true); when(apnsClient.sendNotification(any(SimpleApnsPushNotification.class))) - .thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(executor, invocationOnMock.getArgument(0), new Exception("lost connection"))); + .thenAnswer((Answer) invocationOnMock -> new MockPushNotificationFuture<>(invocationOnMock.getArgument(0), new Exception("lost connection"))); RetryingApnsClient retryingApnsClient = new RetryingApnsClient(apnsClient); ApnMessage message = new ApnMessage(DESTINATION_APN_ID, DESTINATION_NUMBER, 1, true, Optional.empty()); @@ -383,7 +380,7 @@ public class APNSenderTest { verify(apnsClient, times(1)).sendNotification(notification.capture()); assertThat(notification.getValue().getToken()).isEqualTo(DESTINATION_APN_ID); - assertThat(notification.getValue().getExpiration()).isEqualTo(new Date(ApnMessage.MAX_EXPIRATION)); + assertThat(notification.getValue().getExpiration()).isEqualTo(Instant.ofEpochMilli(ApnMessage.MAX_EXPIRATION)); assertThat(notification.getValue().getPayload()).isEqualTo(ApnMessage.APN_NOTIFICATION_PAYLOAD); assertThat(notification.getValue().getPriority()).isEqualTo(DeliveryPriority.IMMEDIATE); @@ -392,31 +389,16 @@ public class APNSenderTest { verifyNoMoreInteractions(fallbackManager); } - private static class MockPushNotificationFuture

extends DefaultPromise implements PushNotificationFuture { + private static class MockPushNotificationFuture

extends PushNotificationFuture { - private final P pushNotification; - - MockPushNotificationFuture(final EventExecutor eventExecutor, final P pushNotification) { - super(eventExecutor); - this.pushNotification = pushNotification; + MockPushNotificationFuture(final P pushNotification, final V response) { + super(pushNotification); + complete(response); } - MockPushNotificationFuture(final EventExecutor eventExecutor, final P pushNotification, final V response) { - super(eventExecutor); - this.pushNotification = pushNotification; - setSuccess(response); - } - - MockPushNotificationFuture(final EventExecutor eventExecutor, final P pushNotification, final Exception exception) { - super(eventExecutor); - this.pushNotification = pushNotification; - setFailure(exception); - } - - - @Override - public P getPushNotification() { - return pushNotification; + MockPushNotificationFuture(final P pushNotification, final Exception exception) { + super(pushNotification); + completeExceptionally(exception); } }