Skip to content

Commit

Permalink
Removed unsupported APNS and replaced it with pushy
Browse files Browse the repository at this point in the history
  • Loading branch information
drallgood committed Sep 9, 2018
1 parent 72e5d76 commit 603a617
Show file tree
Hide file tree
Showing 9 changed files with 267 additions and 53 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -9,8 +9,12 @@ All notable changes to this project will be documented in this file.

### Deprecated

- most methods in `PKSendPushNotificationUtil` deprecated

### Removed

- Removed unsupported APNS dependency and replaced it with [pushy](https://github.com/relayrides/pushy)

### Fixed


Expand Down
19 changes: 19 additions & 0 deletions jpasskit.server/.classpath
Expand Up @@ -15,6 +15,7 @@
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
Expand All @@ -25,12 +26,30 @@
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="target/generated-sources/annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>
19 changes: 19 additions & 0 deletions jpasskit/.classpath
Expand Up @@ -15,11 +15,13 @@
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
Expand All @@ -32,5 +34,22 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="target/generated-sources/annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="target/generated-sources/test-annotations">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="ignore_optional_problems" value="true"/>
<attribute name="m2e-apt" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>
6 changes: 3 additions & 3 deletions jpasskit/pom.xml
Expand Up @@ -108,9 +108,9 @@
</dependency>

<dependency>
<groupId>com.notnoop.apns</groupId>
<artifactId>apns</artifactId>
<version>1.0.0.Beta6</version>
<groupId>com.turo</groupId>
<artifactId>pushy</artifactId>
<version>0.13.4</version>
</dependency>

<dependency>
Expand Down
Expand Up @@ -18,39 +18,48 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;

import javax.net.ssl.SSLException;

import com.turo.pushy.apns.ApnsClient;
import com.turo.pushy.apns.ApnsClientBuilder;
import com.turo.pushy.apns.PushNotificationResponse;
import com.turo.pushy.apns.util.ApnsPayloadBuilder;
import com.turo.pushy.apns.util.SimpleApnsPushNotification;
import com.turo.pushy.apns.util.TokenUtil;
import com.turo.pushy.apns.util.concurrent.PushNotificationFuture;
import com.turo.pushy.apns.util.concurrent.PushNotificationResponseListener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.notnoop.apns.APNS;
import com.notnoop.apns.ApnsDelegate;
import com.notnoop.apns.ApnsNotification;
import com.notnoop.apns.ApnsService;
import com.notnoop.apns.DeliveryError;
import io.netty.util.concurrent.Future;


public class PKSendPushNotificationUtil {

private static final Logger LOGGER = LoggerFactory.getLogger(PKSendPushNotificationUtil.class);
private static final String EMPTY_PUSH_JSON_STRING = "{}";
private ApnsService service;
private ApnsClient client;

public PKSendPushNotificationUtil(final String pathToP12, final String passwordForP12) throws FileNotFoundException {
public PKSendPushNotificationUtil(final String pathToP12, final String passwordForP12) throws FileNotFoundException, SSLException, IOException {
this(pathToP12, passwordForP12, 10);
}

public PKSendPushNotificationUtil(final String pathToP12, final String passwordForP12, final int poolSize) throws FileNotFoundException {

public PKSendPushNotificationUtil(final String pathToP12, final String passwordForP12, final int poolSize) throws FileNotFoundException, SSLException, IOException {
InputStream certificateStream = getStreamOfP12File(pathToP12);
service = APNS.newService().withCert(certificateStream, passwordForP12).withProductionDestination()
.withDelegate(new ApnsLoggingDelegate()).asPool(poolSize).build();
client = new ApnsClientBuilder().setApnsServer(ApnsClientBuilder.PRODUCTION_APNS_HOST, ApnsClientBuilder.DEFAULT_APNS_PORT)
.setClientCredentials(certificateStream,passwordForP12)
.setConcurrentConnections(poolSize)
.build();
}

private InputStream getStreamOfP12File(final String pathToP12) throws FileNotFoundException {
protected InputStream getStreamOfP12File(final String pathToP12) throws FileNotFoundException {
File p12File = new File(pathToP12);
if (!p12File.exists()) {
// try loading it from the classpath
Expand All @@ -63,57 +72,84 @@ private InputStream getStreamOfP12File(final String pathToP12) throws FileNotFou
return new FileInputStream(p12File);
}

@Deprecated(since="0.1.0")
public void sendPushNotification(final String pushtoken) {
try {

PushNotificationFuture<SimpleApnsPushNotification, PushNotificationResponse<SimpleApnsPushNotification>> notificationFuture = sendPushNotificationAsync(pushtoken);
notificationFuture.addListener(new ApnsLoggingDelegate());
final PushNotificationResponse<SimpleApnsPushNotification> pushNotificationResponse = notificationFuture.get();

if (pushNotificationResponse.isAccepted()) {
LOGGER.debug("Push notification accepted by APNs gateway.");
} else {
LOGGER.debug("Notification rejected by the APNs gateway: " +
pushNotificationResponse.getRejectionReason());

if (pushNotificationResponse.getTokenInvalidationTimestamp() != null) {
LOGGER.debug("\t…and the token is invalid as of " +
pushNotificationResponse.getTokenInvalidationTimestamp());
}
}
} catch (final ExecutionException e) {
LOGGER.error("Failed to send push notification.", e);
} catch (final InterruptedException e) {
LOGGER.error("Failed to send push notification.", e);
}
}

public PushNotificationFuture<SimpleApnsPushNotification, PushNotificationResponse<SimpleApnsPushNotification>> sendPushNotificationAsync(final String pushtoken) {

LOGGER.debug("Sending Push notification for key: {}", pushtoken);

final ApnsPayloadBuilder payloadBuilder = new ApnsPayloadBuilder();
payloadBuilder.setAlertBody(EMPTY_PUSH_JSON_STRING);

service.push(pushtoken, EMPTY_PUSH_JSON_STRING);
LOGGER.debug("Send Push notification for key: {}", pushtoken);
final String payload = payloadBuilder.buildWithDefaultMaximumLength();
final String token = TokenUtil.sanitizeTokenString(pushtoken);

SimpleApnsPushNotification pushNotification = new SimpleApnsPushNotification(token, "com.example.myApp", payload);
LOGGER.debug("Send Push notification for key: {}", pushtoken);
return client.sendNotification(pushNotification);
}

@Deprecated(since="0.1.0")
public void sendMultiplePushNotifications(final List<String> pushtokens) {

LOGGER.debug("Sending Push notification for keys: {}", pushtokens);
service.push(pushtokens, EMPTY_PUSH_JSON_STRING);
LOGGER.debug("Send Push notification for keys: {}", pushtokens);

}

public Map<String, Date> getInactiveDevices() {
LOGGER.debug("Querying inactive devices");
Map<String, Date> inactiveDevices = service.getInactiveDevices();
LOGGER.debug("Inactive devices: {}", inactiveDevices);
return inactiveDevices;
}

class ApnsLoggingDelegate implements ApnsDelegate {

@Override
public void messageSendFailed(final ApnsNotification message, final Throwable e) {
LOGGER.debug("Message failed: {}", message, e);
}

@Override
public void connectionClosed(final DeliveryError e, final int messageIdentifier) {
LOGGER.debug("Connection closed: {}", messageIdentifier, e);

}

@Override
public void cacheLengthExceeded(final int newCacheLength) {
LOGGER.debug("CacheLengthExceeded: {}", newCacheLength);
for (String token : pushtokens) {
sendPushNotification(token);
}
}

@Override
public void messageSent(final ApnsNotification message, final boolean resent) {
LOGGER.debug("Message sent: {} (resent={})", message, resent);
public void finalize() {
try {
final Future<Void> closeFuture = client.close();
closeFuture.await();
} catch(Exception e) {
LOGGER.error("error when closing down APNS client",e);
}
}

@Override
public void notificationsResent(final int resendCount) {
LOGGER.debug("Messages resent: {}", resendCount);
class ApnsLoggingDelegate implements PushNotificationResponseListener<SimpleApnsPushNotification> {

@Override
public void operationComplete(final PushNotificationFuture<SimpleApnsPushNotification, PushNotificationResponse<SimpleApnsPushNotification>> future) throws Exception {
// When using a listener, callers should check for a failure to send a
// notification by checking whether the future itself was successful
// since an exception will not be thrown.
if (future.isSuccess()) {
LOGGER.debug("Successfully sent");
} else {
// Something went wrong when trying to send the notification to the
// APNs gateway. We can find the exception that caused the failure
// by getting future.cause().
LOGGER.error("Error sending push notification",future.cause());
}
}
}

public void setClient(ApnsClient newClient) {
client = newClient;
}
}
@@ -0,0 +1,71 @@
/**
* Copyright (C) 2017 Patrice Brend'amour <patrice@brendamour.net>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.brendamour.jpasskit.apns;

import java.io.InputStream;

import com.turo.pushy.apns.ApnsClient;
import com.turo.pushy.apns.ApnsClientBuilder;
import com.turo.pushy.apns.PushNotificationResponse;
import com.turo.pushy.apns.server.AcceptAllPushNotificationHandlerFactory;
import com.turo.pushy.apns.server.MockApnsServer;
import com.turo.pushy.apns.server.MockApnsServerBuilder;
import com.turo.pushy.apns.util.SimpleApnsPushNotification;

import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class PKSendPushNotificationUtilTest {

private PKSendPushNotificationUtil util;
private static final String keyStorePath = "passbook/jpasskittest.p12";
private static final String keyStorePassword = "password";
private static final String CA_CERTIFICATE_FILENAME = "/ca.pem";
private static final String SERVER_CERTIFICATES_FILENAME = "/server-certs.pem";
private static final String SERVER_KEY_FILENAME = "/server-key.pem";
private static final String HOST = "localhost";
private static final int PORT = 8443;

private MockApnsServer apnsServer;

@BeforeClass
public void prepareTest() throws Exception {
util = new PKSendPushNotificationUtil(keyStorePath, keyStorePassword);
InputStream certificateStream = util.getStreamOfP12File(keyStorePath);
ApnsClient client = new ApnsClientBuilder().setApnsServer(HOST,PORT)
.setClientCredentials(certificateStream,keyStorePassword)
.setTrustedServerCertificateChain(getClass().getResourceAsStream(CA_CERTIFICATE_FILENAME))
.build();
util.setClient(client);
apnsServer = new MockApnsServerBuilder().setHandlerFactory(new AcceptAllPushNotificationHandlerFactory()).setServerCredentials(getClass().getResourceAsStream(SERVER_CERTIFICATES_FILENAME), getClass().getResourceAsStream(SERVER_KEY_FILENAME), null)
.build();
apnsServer.start(PORT).await();
}

@Test
public void sendPushNotification() throws Exception {
final PushNotificationResponse<SimpleApnsPushNotification> response = util.sendPushNotificationAsync("ABC1234").get();
Assert.assertTrue(response.isAccepted());
}

@AfterClass
public void shutDownTest() throws Exception {
apnsServer.shutdown();
}
}
19 changes: 19 additions & 0 deletions jpasskit/src/test/resources/ca.pem
@@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDGDCCAgCgAwIBAgIJAPS2GZT4oi8cMA0GCSqGSIb3DQEBDQUAMBgxFjAUBgNV
BAMMDVB1c2h5VGVzdFJvb3QwIBcNMTcwNDE3MDA1MzMwWhgPMjExNzAzMjQwMDUz
MzBaMBgxFjAUBgNVBAMMDVB1c2h5VGVzdFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA
A4IBDwAwggEKAoIBAQDF3Y3kV01ojXWbpZsww9yALoZibzZNOV91ft7DgTqFkHPz
p9J35NHsFSAXF1yHgl/xRnJqP8JC8eqjg/bPE0zzF6ErEaj7zGxDYN3+v0+k6gdL
s+hFWbi38h11lEwj+AejAoOihgHCHjguuhFejGsphFI0HWmR3wXsUIsowzlgmWA6
SUR15gFXbktaPl+XtGxyWcwO5anAUBrwEbChPGNCeLL0fAbBUjKqfw7mhY1OFlv/
LAceM1GdEDvK6mQR4vw+aqypWCX2WPv948rVXegy7VM/lt2YFYEGogtjdrOsT4nd
s/N0/gboq4ebU4mLmsFgJxv0iYU0DFXLw/8hlNHPAgMBAAGjYzBhMB0GA1UdDgQW
BBSxqubF1u3WRgfvF1iaFsKwixZzszAfBgNVHSMEGDAWgBSxqubF1u3WRgfvF1ia
FsKwixZzszAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
9w0BAQ0FAAOCAQEAJ1E2peRR58svomV3gYulC67ktuByiqpJkMBs9AJBzUtQWf/v
s+RUxpRqJawqvfgAtIVuIZAy0zTNkdasQOjSvTkmibQSV61kmyZx0stzwqdKdXfJ
2NbLqfWPd+UyVBKJp+oSGJe7EM/lG1OChDPid57Fn+Vm4SUnv4ly4r0P80buntbk
OWkx3YeCTe6mWa55z+IH7P2Ef0j3V5ui4p7dZ1hOiU2zsIeuGb9jX0h/Tbqyt+mu
93Mgig3e+hgVhNwYEWXzen2SbxzOP2KkRvIjFTNbPuiK8eSPp8RKSME+bc6CY3ZN
UzV5ZWwUxxqk6jHrxrnBt0PxFFGY5gKurTR3+w==
-----END CERTIFICATE-----
18 changes: 18 additions & 0 deletions jpasskit/src/test/resources/server-certs.pem
@@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC8TCCAdmgAwIBAgICbE8wDQYJKoZIhvcNAQENBQAwGDEWMBQGA1UEAwwNUHVz
aHlUZXN0Um9vdDAgFw0xNzA0MTcwMDUzMzBaGA8yMTE3MDMyNDAwNTMzMFowHzEd
MBsGA1UEAwwUY29tLnJlbGF5cmlkZXMucHVzaHkwggEiMA0GCSqGSIb3DQEBAQUA
A4IBDwAwggEKAoIBAQDHZkZBnDKM4Gt+WZwTc5h2GuT1Di7TfUE8SxDhw5wn3c36
41/6lnrTj1Sh5tAsed8N2FDrD+Hp9zTkKljDGe8tuDncT1qSrp/UuikgdIAAiCXA
/vClWPYqZcHAUc9/OcfRiyK5AmJdzz+UbY803ArSPHjz3+Mk6C9tnzBXzG8oJq9o
EKJhwUYX+7l8+m0omtZXhMCOrbmZ2s69m6hTwHJKdC0mEngdyeiYIsbHaoSwxR7U
j8wRstdr2xWhPg1fdIVHzudYubJ7M/h95JQFKtwqEevtLUa4BJgi8SKvRX5NnkGE
QMui1ercRuklVURTeoGDQYENiFnzTyI0J2tw3T+dAgMBAAGjPDA6MAkGA1UdEwQC
MAAwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD
ATANBgkqhkiG9w0BAQ0FAAOCAQEAnHHYMvBWglQLOUmNOalCMopmk9yKHM7+Sc9h
KsTWJW+YohF5zkRhnwUFxW85Pc63rRVA0qyI5zHzRtwYlcZHU57KttJyDGe1rm/0
ZUqXharurJzyI09jcwRpDY8EGktrGirE1iHDqQTHNDHyS8iMVU6aPCo0xur63G5y
XzoIVhQXsBuwoU4VKb3n5CrxKEVcmE/nYF/Tk0rTtCrZF7TR3y/oxrp359goJ1b2
/OjXN4dlqND41SbVTTL0FyXU3ebaS4DALA3pyVa1Rijw7vgEbFabsuMaAbdvlprn
RwUjsrRVu3Tx7sp/NqmeBLVru5nH/yHStDjSdvQtI2ipNGK/9w==
-----END CERTIFICATE-----

0 comments on commit 603a617

Please sign in to comment.