From 192e7205c7554097f126256e4ab0c79d6adc75c1 Mon Sep 17 00:00:00 2001 From: Jude Pereira Date: Fri, 6 Apr 2018 00:06:34 +0530 Subject: [PATCH] Support for connecting to APNs on port 2197. Closes #40 --- .../apns/clients/ApnsClientBuilder.java | 24 ++++++-- .../apns/clients/AsyncOkHttpApnsClient.java | 12 ++++ .../apns/clients/SyncOkHttpApnsClient.java | 60 +++++++++++++++---- 3 files changed, 82 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/clevertap/apns/clients/ApnsClientBuilder.java b/src/main/java/com/clevertap/apns/clients/ApnsClientBuilder.java index 4d3158d..ceaaf93 100644 --- a/src/main/java/com/clevertap/apns/clients/ApnsClientBuilder.java +++ b/src/main/java/com/clevertap/apns/clients/ApnsClientBuilder.java @@ -51,6 +51,7 @@ public class ApnsClientBuilder { private InputStream certificate; private boolean production; private String password; + private int connectionPort = 443; private boolean asynchronous = false; private String defaultTopic = null; @@ -92,6 +93,21 @@ public ApnsClientBuilder withOkHttpClientBuilder(OkHttpClient.Builder clientBuil return this; } + /** + * APNs supports connections over ports 443 and 2197. + * + * @param port Either 443 or 2197 + * @return the builder + */ + public ApnsClientBuilder withPort(final int port) { + if (port != 443 && port != 2197) { + throw new IllegalArgumentException("APNs only supports ports 443 and 2197. Invalid port " + port); + } + + this.connectionPort = port; + return this; + } + public ApnsClientBuilder withConnectionPool(ConnectionPool connectionPool) { this.connectionPool = connectionPool; return this; @@ -167,15 +183,15 @@ public ApnsClient build() throws CertificateException, if (certificate != null) { if (asynchronous) { - return new AsyncOkHttpApnsClient(certificate, password, production, defaultTopic, builder); + return new AsyncOkHttpApnsClient(certificate, password, production, defaultTopic, builder, connectionPort); } else { - return new SyncOkHttpApnsClient(certificate, password, production, defaultTopic, builder); + return new SyncOkHttpApnsClient(certificate, password, production, defaultTopic, builder, connectionPort); } } else if (keyID != null && teamID != null && apnsAuthKey != null) { if (asynchronous) { - return new AsyncOkHttpApnsClient(apnsAuthKey, teamID, keyID, production, defaultTopic, builder); + return new AsyncOkHttpApnsClient(apnsAuthKey, teamID, keyID, production, defaultTopic, builder, connectionPort); } else { - return new SyncOkHttpApnsClient(apnsAuthKey, teamID, keyID, production, defaultTopic, builder); + return new SyncOkHttpApnsClient(apnsAuthKey, teamID, keyID, production, defaultTopic, builder, connectionPort); } } else { throw new IllegalArgumentException("Either the token credentials (team ID, key ID, and the private key) " + diff --git a/src/main/java/com/clevertap/apns/clients/AsyncOkHttpApnsClient.java b/src/main/java/com/clevertap/apns/clients/AsyncOkHttpApnsClient.java index 48eb7d2..4e79ee1 100644 --- a/src/main/java/com/clevertap/apns/clients/AsyncOkHttpApnsClient.java +++ b/src/main/java/com/clevertap/apns/clients/AsyncOkHttpApnsClient.java @@ -62,6 +62,11 @@ public AsyncOkHttpApnsClient(InputStream certificate, String password, boolean p public AsyncOkHttpApnsClient(String apnsAuthKey, String teamID, String keyID, boolean production, String defaultTopic, OkHttpClient.Builder builder) { + this(apnsAuthKey, teamID, keyID, production, defaultTopic, builder, 443); + } + + public AsyncOkHttpApnsClient(String apnsAuthKey, String teamID, String keyID, + boolean production, String defaultTopic, OkHttpClient.Builder builder, int connectionPort) { super(apnsAuthKey, teamID, keyID, production, defaultTopic, builder); } @@ -69,6 +74,13 @@ public AsyncOkHttpApnsClient(InputStream certificate, String password, boolean p String defaultTopic, OkHttpClient.Builder builder) throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, UnrecoverableKeyException, KeyManagementException { + this(certificate, password, production, defaultTopic, builder, 443); + } + + public AsyncOkHttpApnsClient(InputStream certificate, String password, boolean production, + String defaultTopic, OkHttpClient.Builder builder, int connectionPort) + throws CertificateException, NoSuchAlgorithmException, KeyStoreException, + IOException, UnrecoverableKeyException, KeyManagementException { super(certificate, password, production, defaultTopic, builder); } diff --git a/src/main/java/com/clevertap/apns/clients/SyncOkHttpApnsClient.java b/src/main/java/com/clevertap/apns/clients/SyncOkHttpApnsClient.java index d7054ac..3ba261c 100644 --- a/src/main/java/com/clevertap/apns/clients/SyncOkHttpApnsClient.java +++ b/src/main/java/com/clevertap/apns/clients/SyncOkHttpApnsClient.java @@ -73,6 +73,22 @@ public class SyncOkHttpApnsClient implements ApnsClient { */ public SyncOkHttpApnsClient(String apnsAuthKey, String teamID, String keyID, boolean production, String defaultTopic, OkHttpClient.Builder clientBuilder) { + this(apnsAuthKey, teamID, keyID, production, defaultTopic, clientBuilder, 443); + } + + /** + * Creates a new client which uses token authentication API. + * + * @param apnsAuthKey The private key - exclude -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY----- + * @param teamID The team ID + * @param keyID The key ID (retrieved from the file name) + * @param production Whether to use the production endpoint or the sandbox endpoint + * @param defaultTopic A default topic (can be changed per message) + * @param clientBuilder An OkHttp client builder, possibly pre-initialized, to build the actual client + * @param connectionPort The port to establish a connection with APNs. Either 443 or 2197 + */ + public SyncOkHttpApnsClient(String apnsAuthKey, String teamID, String keyID, boolean production, + String defaultTopic, OkHttpClient.Builder clientBuilder, int connectionPort) { this.apnsAuthKey = apnsAuthKey; this.teamID = teamID; this.keyID = keyID; @@ -80,7 +96,7 @@ public SyncOkHttpApnsClient(String apnsAuthKey, String teamID, String keyID, boo this.defaultTopic = defaultTopic; - gateway = production ? Constants.ENDPOINT_PRODUCTION : Constants.ENDPOINT_SANDBOX; + gateway = (production ? Constants.ENDPOINT_PRODUCTION : Constants.ENDPOINT_SANDBOX) + ":" + connectionPort; } /** @@ -103,11 +119,11 @@ public SyncOkHttpApnsClient(String apnsAuthKey, String teamID, String keyID, boo * Creates a new client and automatically loads the key store * with the push certificate read from the input stream. * - * @param certificate The client certificate to be used - * @param password The password (if required, else null) - * @param production Whether to use the production endpoint or the sandbox endpoint - * @param defaultTopic A default topic (can be changed per message) - * @param builder An OkHttp client builder, possibly pre-initialized, to build the actual client + * @param certificate The client certificate to be used + * @param password The password (if required, else null) + * @param production Whether to use the production endpoint or the sandbox endpoint + * @param defaultTopic A default topic (can be changed per message) + * @param builder An OkHttp client builder, possibly pre-initialized, to build the actual client * @throws UnrecoverableKeyException If the key cannot be recovered * @throws KeyManagementException if the key failed to be loaded * @throws CertificateException if any of the certificates in the keystore could not be loaded @@ -120,6 +136,31 @@ public SyncOkHttpApnsClient(InputStream certificate, String password, boolean pr String defaultTopic, OkHttpClient.Builder builder) throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, UnrecoverableKeyException, KeyManagementException { + this(certificate, password, production, defaultTopic, builder, 443); + } + + /** + * Creates a new client and automatically loads the key store + * with the push certificate read from the input stream. + * + * @param certificate The client certificate to be used + * @param password The password (if required, else null) + * @param production Whether to use the production endpoint or the sandbox endpoint + * @param defaultTopic A default topic (can be changed per message) + * @param builder An OkHttp client builder, possibly pre-initialized, to build the actual client + * @param connectionPort The port to establish a connection with APNs. Either 443 or 2197 + * @throws UnrecoverableKeyException If the key cannot be recovered + * @throws KeyManagementException if the key failed to be loaded + * @throws CertificateException if any of the certificates in the keystore could not be loaded + * @throws NoSuchAlgorithmException if the algorithm used to check the integrity of the keystore cannot be found + * @throws IOException if there is an I/O or format problem with the keystore data, + * if a password is required but not given, or if the given password was incorrect + * @throws KeyStoreException if no Provider supports a KeyStoreSpi implementation for the specified type + */ + public SyncOkHttpApnsClient(InputStream certificate, String password, boolean production, + String defaultTopic, OkHttpClient.Builder builder, int connectionPort) + throws CertificateException, NoSuchAlgorithmException, KeyStoreException, + IOException, UnrecoverableKeyException, KeyManagementException { teamID = keyID = apnsAuthKey = null; @@ -146,7 +187,7 @@ public SyncOkHttpApnsClient(InputStream certificate, String password, boolean pr client = builder.build(); this.defaultTopic = defaultTopic; - gateway = production ? Constants.ENDPOINT_PRODUCTION : Constants.ENDPOINT_SANDBOX; + gateway = (production ? Constants.ENDPOINT_PRODUCTION : Constants.ENDPOINT_SANDBOX) + ":" + connectionPort; } /** @@ -209,7 +250,6 @@ protected final Request buildRequest(Notification notification) { final Notification.Priority priority = notification.getPriority(); Request.Builder rb = new Request.Builder() .url(gateway + "/3/device/" + notification.getToken()) - .post(new RequestBody() { @Override public MediaType contentType() { @@ -232,7 +272,7 @@ public void writeTo(BufferedSink sink) throws IOException { } if (uuid != null) { - rb.header("apns-id",uuid.toString()); + rb.header("apns-id", uuid.toString()); } if (expiration > -1) { @@ -240,7 +280,7 @@ public void writeTo(BufferedSink sink) throws IOException { } if (priority != null) { - rb.header("apns-priority",String.valueOf(priority.getCode())); + rb.header("apns-priority", String.valueOf(priority.getCode())); } if (keyID != null && teamID != null && apnsAuthKey != null) {