getInactiveDevices() throws NetworkIOException;
-
- /**
- * Test that the service is setup properly and the Apple servers
- * are reachable.
- *
- * @throws NetworkIOException if the Apple servers aren't reachable
- * or the service cannot send notifications for now
- */
- void testConnection() throws NetworkIOException;
-
-}
diff --git a/src/main/java/com/notnoop/apns/ApnsServiceBuilder.java b/src/main/java/com/notnoop/apns/ApnsServiceBuilder.java
deleted file mode 100644
index abc01f3b..00000000
--- a/src/main/java/com/notnoop/apns/ApnsServiceBuilder.java
+++ /dev/null
@@ -1,760 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns;
-
-import com.notnoop.apns.internal.ApnsConnection;
-import com.notnoop.apns.internal.ApnsConnectionImpl;
-import com.notnoop.apns.internal.ApnsFeedbackConnection;
-import com.notnoop.apns.internal.ApnsPooledConnection;
-import com.notnoop.apns.internal.ApnsServiceImpl;
-import com.notnoop.apns.internal.BatchApnsService;
-import com.notnoop.apns.internal.QueuedApnsService;
-import com.notnoop.apns.internal.SSLContextBuilder;
-import com.notnoop.apns.internal.Utilities;
-import com.notnoop.exceptions.InvalidSSLConfig;
-import com.notnoop.exceptions.RuntimeIOException;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSocketFactory;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.net.InetSocketAddress;
-import java.net.Proxy;
-import java.net.Socket;
-import java.security.KeyStore;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.ThreadFactory;
-
-import static com.notnoop.apns.internal.Utilities.PRODUCTION_FEEDBACK_HOST;
-import static com.notnoop.apns.internal.Utilities.PRODUCTION_FEEDBACK_PORT;
-import static com.notnoop.apns.internal.Utilities.PRODUCTION_GATEWAY_HOST;
-import static com.notnoop.apns.internal.Utilities.PRODUCTION_GATEWAY_PORT;
-import static com.notnoop.apns.internal.Utilities.SANDBOX_FEEDBACK_HOST;
-import static com.notnoop.apns.internal.Utilities.SANDBOX_FEEDBACK_PORT;
-import static com.notnoop.apns.internal.Utilities.SANDBOX_GATEWAY_HOST;
-import static com.notnoop.apns.internal.Utilities.SANDBOX_GATEWAY_PORT;
-import static java.util.concurrent.Executors.defaultThreadFactory;
-
-/**
- * The class is used to create instances of {@link ApnsService}.
- *
- * Note that this class is not synchronized. If multiple threads access a
- * {@code ApnsServiceBuilder} instance concurrently, and at least on of the
- * threads modifies one of the attributes structurally, it must be
- * synchronized externally.
- *
- * Starting a new {@code ApnsService} is easy:
- *
- *
- * ApnsService = APNS.newService()
- * .withCert("/path/to/certificate.p12", "MyCertPassword")
- * .withSandboxDestination()
- * .build()
- *
- */
-public class ApnsServiceBuilder {
- private static final String KEYSTORE_TYPE = "PKCS12";
- private static final String KEY_ALGORITHM = ((java.security.Security.getProperty("ssl.KeyManagerFactory.algorithm") == null)? "sunx509" : java.security.Security.getProperty("ssl.KeyManagerFactory.algorithm"));
-
- private SSLContext sslContext;
-
- private int readTimeout;
- private int connectTimeout;
-
- private String gatewayHost;
- private int gatewayPort = -1;
-
- private String feedbackHost;
- private int feedbackPort;
- private int pooledMax = 1;
- private int cacheLength = ApnsConnection.DEFAULT_CACHE_LENGTH;
- private boolean autoAdjustCacheLength = true;
- private ExecutorService executor;
-
- private ReconnectPolicy reconnectPolicy = ReconnectPolicy.Provided.EVERY_HALF_HOUR.newObject();
- private boolean isQueued;
- private ThreadFactory queueThreadFactory;
-
- private boolean isBatched;
- private int batchWaitTimeInSec;
- private int batchMaxWaitTimeInSec;
- private ScheduledExecutorService batchThreadPoolExecutor;
-
- private ApnsDelegate delegate = ApnsDelegate.EMPTY;
- private Proxy proxy;
- private String proxyUsername;
- private String proxyPassword;
- private boolean errorDetection = true;
- private ThreadFactory errorDetectionThreadFactory;
-
- /**
- * Constructs a new instance of {@code ApnsServiceBuilder}
- */
- public ApnsServiceBuilder() { sslContext = null; }
-
- /**
- * Specify the certificate used to connect to Apple APNS
- * servers. This relies on the path (absolute or relative to
- * working path) to the keystore (*.p12) containing the
- * certificate, along with the given password.
- *
- * The keystore needs to be of PKCS12 and the keystore
- * needs to be encrypted using the SunX509 algorithm. Both
- * of these settings are the default.
- *
- * This library does not support password-less p12 certificates, due to a
- * Oracle Java library
- * Bug 6415637. There are three workarounds: use a password-protected
- * certificate, use a different boot Java SDK implementation, or construct
- * the `SSLContext` yourself! Needless to say, the password-protected
- * certificate is most recommended option.
- *
- * @param fileName the path to the certificate
- * @param password the password of the keystore
- * @return this
- * @throws RuntimeIOException if it {@code fileName} cannot be
- * found or read
- * @throws InvalidSSLConfig if fileName is invalid Keystore
- * or the password is invalid
- */
- public ApnsServiceBuilder withCert(String fileName, String password)
- throws RuntimeIOException, InvalidSSLConfig {
- FileInputStream stream = null;
- try {
- stream = new FileInputStream(fileName);
- return withCert(stream, password);
- } catch (FileNotFoundException e) {
- throw new RuntimeIOException(e);
- } finally {
- Utilities.close(stream);
- }
- }
-
- /**
- * Specify the certificate used to connect to Apple APNS
- * servers. This relies on the stream of keystore (*.p12)
- * containing the certificate, along with the given password.
- *
- * The keystore needs to be of PKCS12 and the keystore
- * needs to be encrypted using the SunX509 algorithm. Both
- * of these settings are the default.
- *
- * This library does not support password-less p12 certificates, due to a
- * Oracle Java library
- * Bug 6415637. There are three workarounds: use a password-protected
- * certificate, use a different boot Java SDK implementation, or constract
- * the `SSLContext` yourself! Needless to say, the password-protected
- * certificate is most recommended option.
- *
- * @param stream the keystore represented as input stream
- * @param password the password of the keystore
- * @return this
- * @throws InvalidSSLConfig if stream is invalid Keystore
- * or the password is invalid
- */
- public ApnsServiceBuilder withCert(InputStream stream, String password)
- throws InvalidSSLConfig {
- assertPasswordNotEmpty(password);
- return withSSLContext(new SSLContextBuilder()
- .withAlgorithm(KEY_ALGORITHM)
- .withCertificateKeyStore(stream, password, KEYSTORE_TYPE)
- .withDefaultTrustKeyStore()
- .build());
- }
-
- /**
- * Specify the certificate used to connect to Apple APNS
- * servers. This relies on a keystore (*.p12)
- * containing the certificate, along with the given password.
- *
- * This library does not support password-less p12 certificates, due to a
- * Oracle Java library
- * Bug 6415637. There are three workarounds: use a password-protected
- * certificate, use a different boot Java SDK implementation, or construct
- * the `SSLContext` yourself! Needless to say, the password-protected
- * certificate is most recommended option.
- *
- * @param keyStore the keystore
- * @param password the password of the keystore
- * @return this
- * @throws InvalidSSLConfig if stream is invalid Keystore
- * or the password is invalid
- */
- public ApnsServiceBuilder withCert(KeyStore keyStore, String password)
- throws InvalidSSLConfig {
- assertPasswordNotEmpty(password);
- return withSSLContext(new SSLContextBuilder()
- .withAlgorithm(KEY_ALGORITHM)
- .withCertificateKeyStore(keyStore, password)
- .withDefaultTrustKeyStore()
- .build());
- }
-
- /**
- * Specify the certificate store used to connect to Apple APNS
- * servers. This relies on the stream of keystore (*.p12 | *.jks)
- * containing the keys and certificates, along with the given
- * password and alias.
- *
- * The keystore can be either PKCS12 or JKS and the keystore
- * needs to be encrypted using the SunX509 algorithm.
- *
- * This library does not support password-less p12 certificates, due to a
- * Oracle Java library
- * Bug 6415637. There are three workarounds: use a password-protected
- * certificate, use a different boot Java SDK implementation, or constract
- * the `SSLContext` yourself! Needless to say, the password-protected
- * certificate is most recommended option.
- *
- * @param stream the keystore represented as input stream
- * @param password the password of the keystore
- * @param alias the alias identifing the key to be used
- * @return this
- * @throws InvalidSSLConfig if stream is an invalid Keystore,
- * the password is invalid or the alias is not found
- */
- public ApnsServiceBuilder withCert(InputStream stream, String password, String alias)
- throws InvalidSSLConfig {
- assertPasswordNotEmpty(password);
- return withSSLContext(new SSLContextBuilder()
- .withAlgorithm(KEY_ALGORITHM)
- .withCertificateKeyStore(stream, password, KEYSTORE_TYPE, alias)
- .withDefaultTrustKeyStore()
- .build());
- }
-
- /**
- * Specify the certificate store used to connect to Apple APNS
- * servers. This relies on the stream of keystore (*.p12 | *.jks)
- * containing the keys and certificates, along with the given
- * password and alias.
- *
- * The keystore can be either PKCS12 or JKS and the keystore
- * needs to be encrypted using the SunX509 algorithm.
- *
- * This library does not support password-less p12 certificates, due to a
- * Oracle Java library
- * Bug 6415637. There are three workarounds: use a password-protected
- * certificate, use a different boot Java SDK implementation, or constract
- * the `SSLContext` yourself! Needless to say, the password-protected
- * certificate is most recommended option.
- *
- * @param keyStore the keystore
- * @param password the password of the keystore
- * @param alias the alias identifing the key to be used
- * @return this
- * @throws InvalidSSLConfig if stream is an invalid Keystore,
- * the password is invalid or the alias is not found
- */
- public ApnsServiceBuilder withCert(KeyStore keyStore, String password, String alias)
- throws InvalidSSLConfig {
- assertPasswordNotEmpty(password);
- return withSSLContext(new SSLContextBuilder()
- .withAlgorithm(KEY_ALGORITHM)
- .withCertificateKeyStore(keyStore, password, alias)
- .withDefaultTrustKeyStore()
- .build());
- }
-
- private void assertPasswordNotEmpty(String password) {
- if (password == null || password.length() == 0) {
- throw new IllegalArgumentException("Passwords must be specified." +
- "Oracle Java SDK does not support passwordless p12 certificates");
- }
- }
-
- /**
- * Specify the SSLContext that should be used to initiate the
- * connection to Apple Server.
- *
- * Most clients would use {@link #withCert(InputStream, String)}
- * or {@link #withCert(String, String)} instead. But some
- * clients may need to represent the Keystore in a different
- * format than supported.
- *
- * @param sslContext Context to be used to create secure connections
- * @return this
- */
- public ApnsServiceBuilder withSSLContext(SSLContext sslContext) {
- this.sslContext = sslContext;
- return this;
- }
-
- /**
- * Specify the timeout value to be set in new setSoTimeout in created
- * sockets, for both feedback and push connections, in milliseconds.
- * @param readTimeout timeout value to be set in new setSoTimeout
- * @return this
- */
- public ApnsServiceBuilder withReadTimeout(int readTimeout) {
- this.readTimeout = readTimeout;
- return this;
- }
-
- /**
- * Specify the timeout value to use for connectionTimeout in created
- * sockets, for both feedback and push connections, in milliseconds.
- * @param connectTimeout timeout value to use for connectionTimeout
- * @return this
- */
- public ApnsServiceBuilder withConnectTimeout(int connectTimeout) {
- this.connectTimeout = connectTimeout;
- return this;
- }
-
- /**
- * Specify the gateway server for sending Apple iPhone
- * notifications.
- *
- * Most clients should use {@link #withSandboxDestination()}
- * or {@link #withProductionDestination()}. Clients may use
- * this method to connect to mocking tests and such.
- *
- * @param host hostname the notification gateway of Apple
- * @param port port of the notification gateway of Apple
- * @return this
- */
- public ApnsServiceBuilder withGatewayDestination(String host, int port) {
- this.gatewayHost = host;
- this.gatewayPort = port;
- return this;
- }
-
- /**
- * Specify the Feedback for getting failed devices from
- * Apple iPhone Push servers.
- *
- * Most clients should use {@link #withSandboxDestination()}
- * or {@link #withProductionDestination()}. Clients may use
- * this method to connect to mocking tests and such.
- *
- * @param host hostname of the feedback server of Apple
- * @param port port of the feedback server of Apple
- * @return this
- */
- public ApnsServiceBuilder withFeedbackDestination(String host, int port) {
- this.feedbackHost = host;
- this.feedbackPort = port;
- return this;
- }
-
- /**
- * Specify to use Apple servers as iPhone gateway and feedback servers.
- *
- * If the passed {@code isProduction} is true, then it connects to the
- * production servers, otherwise, it connects to the sandbox servers
- *
- * @param isProduction determines which Apple servers should be used:
- * production or sandbox
- * @return this
- */
- public ApnsServiceBuilder withAppleDestination(boolean isProduction) {
- if (isProduction) {
- return withProductionDestination();
- } else {
- return withSandboxDestination();
- }
- }
-
- /**
- * Specify to use the Apple sandbox servers as iPhone gateway
- * and feedback servers.
- *
- * This is desired when in testing and pushing notifications
- * with a development provision.
- *
- * @return this
- */
- public ApnsServiceBuilder withSandboxDestination() {
- return withGatewayDestination(SANDBOX_GATEWAY_HOST, SANDBOX_GATEWAY_PORT)
- .withFeedbackDestination(SANDBOX_FEEDBACK_HOST, SANDBOX_FEEDBACK_PORT);
- }
-
- /**
- * Specify to use the Apple Production servers as iPhone gateway
- * and feedback servers.
- *
- * This is desired when sending notifications to devices with
- * a production provision (whether through App Store or Ad hoc
- * distribution).
- *
- * @return this
- */
- public ApnsServiceBuilder withProductionDestination() {
- return withGatewayDestination(PRODUCTION_GATEWAY_HOST, PRODUCTION_GATEWAY_PORT)
- .withFeedbackDestination(PRODUCTION_FEEDBACK_HOST, PRODUCTION_FEEDBACK_PORT);
- }
-
- /**
- * Specify the reconnection policy for the socket connection.
- *
- * Note: This option has no effect when using non-blocking
- * connections.
- */
- public ApnsServiceBuilder withReconnectPolicy(ReconnectPolicy rp) {
- this.reconnectPolicy = rp;
- return this;
- }
-
- /**
- * Specify if the notification cache should auto adjust.
- * Default is true
- *
- * @param autoAdjustCacheLength the notification cache should auto adjust.
- * @return this
- */
- public ApnsServiceBuilder withAutoAdjustCacheLength(boolean autoAdjustCacheLength) {
- this.autoAdjustCacheLength = autoAdjustCacheLength;
- return this;
- }
-
- /**
- * Specify the reconnection policy for the socket connection.
- *
- * Note: This option has no effect when using non-blocking
- * connections.
- */
- public ApnsServiceBuilder withReconnectPolicy(ReconnectPolicy.Provided rp) {
- this.reconnectPolicy = rp.newObject();
- return this;
- }
-
- /**
- * Specify the address of the SOCKS proxy the connection should
- * use.
- *
- * Read the
- * Java Networking and Proxies guide to understand the
- * proxies complexity.
- *
- *
Be aware that this method only handles SOCKS proxies, not
- * HTTPS proxies. Use {@link #withProxy(Proxy)} instead.
- *
- * @param host the hostname of the SOCKS proxy
- * @param port the port of the SOCKS proxy server
- * @return this
- */
- public ApnsServiceBuilder withSocksProxy(String host, int port) {
- Proxy proxy = new Proxy(Proxy.Type.SOCKS,
- new InetSocketAddress(host, port));
- return withProxy(proxy);
- }
-
- /**
- * Specify the proxy and the authentication parameters to be used
- * to establish the connections to Apple Servers.
- *
- *
Read the
- * Java Networking and Proxies guide to understand the
- * proxies complexity.
- *
- * @param proxy the proxy object to be used to create connections
- * @param proxyUsername a String object representing the username of the proxy server
- * @param proxyPassword a String object representing the password of the proxy server
- * @return this
- */
- public ApnsServiceBuilder withAuthProxy(Proxy proxy, String proxyUsername, String proxyPassword) {
- this.proxy = proxy;
- this.proxyUsername = proxyUsername;
- this.proxyPassword = proxyPassword;
- return this;
- }
-
- /**
- * Specify the proxy to be used to establish the connections
- * to Apple Servers
- *
- *
Read the
- * Java Networking and Proxies guide to understand the
- * proxies complexity.
- *
- * @param proxy the proxy object to be used to create connections
- * @return this
- */
- public ApnsServiceBuilder withProxy(Proxy proxy) {
- this.proxy = proxy;
- return this;
- }
-
- /**
- * Specify the number of notifications to cache for error purposes.
- * Default is 100
- *
- * @param cacheLength Number of notifications to cache for error purposes
- * @return this
- */
- public ApnsServiceBuilder withCacheLength(int cacheLength) {
- this.cacheLength = cacheLength;
- return this;
- }
-
- /**
- * Specify the socket to be used as underlying socket to connect
- * to the APN service.
- *
- * This assumes that the socket connects to a SOCKS proxy.
- *
- * @deprecated use {@link ApnsServiceBuilder#withProxy(Proxy)} instead
- * @param proxySocket the underlying socket for connections
- * @return this
- */
- @Deprecated
- public ApnsServiceBuilder withProxySocket(Socket proxySocket) {
- return this.withProxy(new Proxy(Proxy.Type.SOCKS,
- proxySocket.getRemoteSocketAddress()));
- }
-
- /**
- * Constructs a pool of connections to the notification servers.
- *
- * Apple servers recommend using a pooled connection up to
- * 15 concurrent persistent connections to the gateways.
- *
- * Note: This option has no effect when using non-blocking
- * connections.
- */
- public ApnsServiceBuilder asPool(int maxConnections) {
- return asPool(Executors.newFixedThreadPool(maxConnections), maxConnections);
- }
-
- /**
- * Constructs a pool of connections to the notification servers.
- *
- * Apple servers recommend using a pooled connection up to
- * 15 concurrent persistent connections to the gateways.
- *
- * Note: This option has no effect when using non-blocking
- * connections.
- *
- * Note: The maxConnections here is used as a hint to how many connections
- * get created.
- */
- public ApnsServiceBuilder asPool(ExecutorService executor, int maxConnections) {
- this.pooledMax = maxConnections;
- this.executor = executor;
- return this;
- }
-
- /**
- * Constructs a new thread with a processing queue to process
- * notification requests.
- *
- * @return this
- */
- public ApnsServiceBuilder asQueued() {
- return asQueued(Executors.defaultThreadFactory());
- }
-
- /**
- * Constructs a new thread with a processing queue to process
- * notification requests.
- *
- * @param threadFactory
- * thread factory to use for queue processing
- * @return this
- */
- public ApnsServiceBuilder asQueued(ThreadFactory threadFactory) {
- this.isQueued = true;
- this.queueThreadFactory = threadFactory;
- return this;
- }
-
- /**
- * Construct service which will process notification requests in batch.
- * After each request batch will wait waitTimeInSec (set as 5sec) for more request to come
- * before executing but not more than maxWaitTimeInSec (set as 10sec)
- *
- * Note: It is not recommended to use pooled connection
- */
- public ApnsServiceBuilder asBatched() {
- return asBatched(5, 10);
- }
-
- /**
- * Construct service which will process notification requests in batch.
- * After each request batch will wait waitTimeInSec for more request to come
- * before executing but not more than maxWaitTimeInSec
- *
- * Note: It is not recommended to use pooled connection
- *
- * @param waitTimeInSec
- * time to wait for more notification request before executing
- * batch
- * @param maxWaitTimeInSec
- * maximum wait time for batch before executing
- */
- public ApnsServiceBuilder asBatched(int waitTimeInSec, int maxWaitTimeInSec) {
- return asBatched(waitTimeInSec, maxWaitTimeInSec, (ThreadFactory)null);
- }
-
- /**
- * Construct service which will process notification requests in batch.
- * After each request batch will wait waitTimeInSec for more request to come
- * before executing but not more than maxWaitTimeInSec
- *
- * Each batch creates new connection and close it after finished.
- * In case reconnect policy is specified it will be applied by batch processing.
- * E.g.: {@link ReconnectPolicy.Provided#EVERY_HALF_HOUR} will reconnect the connection in case batch is running for more than half an hour
- *
- * Note: It is not recommended to use pooled connection
- *
- * @param waitTimeInSec
- * time to wait for more notification request before executing
- * batch
- * @param maxWaitTimeInSec
- * maximum wait time for batch before executing
- * @param threadFactory
- * thread factory to use for batch processing
- */
- public ApnsServiceBuilder asBatched(int waitTimeInSec, int maxWaitTimeInSec, ThreadFactory threadFactory) {
- return asBatched(waitTimeInSec, maxWaitTimeInSec, new ScheduledThreadPoolExecutor(1, threadFactory != null ? threadFactory : defaultThreadFactory()));
- }
-
- /**
- * Construct service which will process notification requests in batch.
- * After each request batch will wait waitTimeInSec for more request to come
- * before executing but not more than maxWaitTimeInSec
- *
- * Each batch creates new connection and close it after finished.
- * In case reconnect policy is specified it will be applied by batch processing.
- * E.g.: {@link ReconnectPolicy.Provided#EVERY_HALF_HOUR} will reconnect the connection in case batch is running for more than half an hour
- *
- * Note: It is not recommended to use pooled connection
- *
- * @param waitTimeInSec
- * time to wait for more notification request before executing
- * batch
- * @param maxWaitTimeInSec
- * maximum wait time for batch before executing
- * @param batchThreadPoolExecutor
- * executor for batched processing (may be null)
- */
- public ApnsServiceBuilder asBatched(int waitTimeInSec, int maxWaitTimeInSec, ScheduledExecutorService batchThreadPoolExecutor) {
- this.isBatched = true;
- this.batchWaitTimeInSec = waitTimeInSec;
- this.batchMaxWaitTimeInSec = maxWaitTimeInSec;
- this.batchThreadPoolExecutor = batchThreadPoolExecutor;
- return this;
- }
-
- /**
- * Sets the delegate of the service, that gets notified of the
- * status of message delivery.
- *
- * Note: This option has no effect when using non-blocking
- * connections.
- */
- public ApnsServiceBuilder withDelegate(ApnsDelegate delegate) {
- this.delegate = delegate == null ? ApnsDelegate.EMPTY : delegate;
- return this;
- }
-
- /**
- * Disables the enhanced error detection, enabled by the
- * enhanced push notification interface. Error detection is
- * enabled by default.
- *
- * This setting is desired when the application shouldn't spawn
- * new threads.
- *
- * @return this
- */
- public ApnsServiceBuilder withNoErrorDetection() {
- this.errorDetection = false;
- return this;
- }
-
- /**
- * Provide a custom source for threads used for monitoring connections.
- *
- * This setting is desired when the application must obtain threads from a
- * controlled environment Google App Engine.
- * @param threadFactory
- * thread factory to use for error detection
- * @return this
- */
- public ApnsServiceBuilder withErrorDetectionThreadFactory(ThreadFactory threadFactory) {
- this.errorDetectionThreadFactory = threadFactory;
- return this;
- }
-
- /**
- * Returns a fully initialized instance of {@link ApnsService},
- * according to the requested settings.
- *
- * @return a new instance of ApnsService
- */
- public ApnsService build() {
- checkInitialization();
- ApnsService service;
-
- SSLSocketFactory sslFactory = sslContext.getSocketFactory();
- ApnsFeedbackConnection feedback = new ApnsFeedbackConnection(sslFactory, feedbackHost, feedbackPort, proxy, readTimeout, connectTimeout, proxyUsername, proxyPassword);
-
- ApnsConnection conn = new ApnsConnectionImpl(sslFactory, gatewayHost,
- gatewayPort, proxy, proxyUsername, proxyPassword, reconnectPolicy,
- delegate, errorDetection, errorDetectionThreadFactory, cacheLength,
- autoAdjustCacheLength, readTimeout, connectTimeout);
- if (pooledMax != 1) {
- conn = new ApnsPooledConnection(conn, pooledMax, executor);
- }
-
- service = new ApnsServiceImpl(conn, feedback);
-
- if (isQueued) {
- service = new QueuedApnsService(service, queueThreadFactory);
- }
-
- if (isBatched) {
- service = new BatchApnsService(conn, feedback, batchWaitTimeInSec, batchMaxWaitTimeInSec, batchThreadPoolExecutor);
- }
-
- service.start();
-
- return service;
- }
-
- private void checkInitialization() {
- if (sslContext == null)
- throw new IllegalStateException(
- "SSL Certificates and attribute are not initialized\n"
- + "Use .withCert() methods.");
- if (gatewayHost == null || gatewayPort == -1)
- throw new IllegalStateException(
- "The Destination APNS server is not stated\n"
- + "Use .withDestination(), withSandboxDestination(), "
- + "or withProductionDestination().");
- }
-}
diff --git a/src/main/java/com/notnoop/apns/DeliveryError.java b/src/main/java/com/notnoop/apns/DeliveryError.java
deleted file mode 100644
index 4ba33f64..00000000
--- a/src/main/java/com/notnoop/apns/DeliveryError.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns;
-
-/**
- * Errors in delivery that may get reported by Apple APN servers
- */
-public enum DeliveryError {
- /**
- * Connection closed without any error.
- *
- * This may occur if the APN service faces an invalid simple
- * APNS notification while running in enhanced mode
- */
- NO_ERROR(0),
- PROCESSING_ERROR(1),
- MISSING_DEVICE_TOKEN(2),
- MISSING_TOPIC(3),
- MISSING_PAYLOAD(4),
- INVALID_TOKEN_SIZE(5),
- INVALID_TOPIC_SIZE(6),
- INVALID_PAYLOAD_SIZE(7),
- INVALID_TOKEN(8),
-
- NONE(255),
- UNKNOWN(254);
-
- private final byte code;
- DeliveryError(int code) {
- this.code = (byte)code;
- }
-
- /** The status code as specified by Apple */
- public int code() {
- return code;
- }
-
- /**
- * Returns the appropriate {@code DeliveryError} enum
- * corresponding to the Apple provided status code
- *
- * @param code status code provided by Apple
- * @return the appropriate DeliveryError
- */
- public static DeliveryError ofCode(int code) {
- for (DeliveryError e : DeliveryError.values()) {
- if (e.code == code)
- return e;
- }
-
- return UNKNOWN;
- }
-}
diff --git a/src/main/java/com/notnoop/apns/EnhancedApnsNotification.java b/src/main/java/com/notnoop/apns/EnhancedApnsNotification.java
deleted file mode 100644
index 23fbab4e..00000000
--- a/src/main/java/com/notnoop/apns/EnhancedApnsNotification.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns;
-
-import java.util.Arrays;
-import java.util.concurrent.atomic.AtomicInteger;
-import com.notnoop.apns.internal.Utilities;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import java.io.UnsupportedEncodingException;
-
-/**
- * Represents an APNS notification to be sent to Apple service.
- */
-public class EnhancedApnsNotification implements ApnsNotification {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(EnhancedApnsNotification.class);
- private final static byte COMMAND = 1;
- private static AtomicInteger nextId = new AtomicInteger(0);
- private final int identifier;
- private final int expiry;
- private final byte[] deviceToken;
- private final byte[] payload;
-
- public static int INCREMENT_ID() {
- return nextId.incrementAndGet();
- }
-
- /**
- * The infinite future for the purposes of Apple expiry date
- */
- public final static int MAXIMUM_EXPIRY = Integer.MAX_VALUE;
-
- /**
- * Constructs an instance of {@code ApnsNotification}.
- *
- * The message encodes the payload with a {@code UTF-8} encoding.
- *
- * @param dtoken The Hex of the device token of the destination phone
- * @param payload The payload message to be sent
- */
- public EnhancedApnsNotification(
- int identifier, int expiryTime,
- String dtoken, String payload) {
- this.identifier = identifier;
- this.expiry = expiryTime;
- this.deviceToken = Utilities.decodeHex(dtoken);
- this.payload = Utilities.toUTF8Bytes(payload);
- }
-
- /**
- * Constructs an instance of {@code ApnsNotification}.
- *
- * @param dtoken The binary representation of the destination device token
- * @param payload The binary representation of the payload to be sent
- */
- public EnhancedApnsNotification(
- int identifier, int expiryTime,
- byte[] dtoken, byte[] payload) {
- this.identifier = identifier;
- this.expiry = expiryTime;
- this.deviceToken = Utilities.copyOf(dtoken);
- this.payload = Utilities.copyOf(payload);
- }
-
- /**
- * Returns the binary representation of the device token.
- *
- */
- public byte[] getDeviceToken() {
- return Utilities.copyOf(deviceToken);
- }
-
- /**
- * Returns the binary representation of the payload.
- *
- */
- public byte[] getPayload() {
- return Utilities.copyOf(payload);
- }
-
- public int getIdentifier() {
- return identifier;
- }
-
- public int getExpiry() {
- return expiry;
- }
-
- private byte[] marshall;
- /**
- * Returns the binary representation of the message as expected by the
- * APNS server.
- *
- * The returned array can be used to sent directly to the APNS server
- * (on the wire/socket) without any modification.
- */
- public byte[] marshall() {
- if (marshall == null) {
- marshall = Utilities.marshallEnhanced(COMMAND, identifier,
- expiry, deviceToken, payload);
- }
- return marshall.clone();
- }
-
- /**
- * Returns the length of the message in bytes as it is encoded on the wire.
- *
- * Apple require the message to be of length 255 bytes or less.
- *
- * @return length of encoded message in bytes
- */
- public int length() {
- int length = 1 + 4 + 4 + 2 + deviceToken.length + 2 + payload.length;
- final int marshalledLength = marshall().length;
- assert marshalledLength == length;
- return length;
- }
-
- @Override
- public int hashCode() {
- return (21
- + 31 * identifier
- + 31 * expiry
- + 31 * Arrays.hashCode(deviceToken)
- + 31 * Arrays.hashCode(payload));
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof EnhancedApnsNotification))
- return false;
- EnhancedApnsNotification o = (EnhancedApnsNotification)obj;
- return (identifier == o.identifier
- && expiry == o.expiry
- && Arrays.equals(this.deviceToken, o.deviceToken)
- && Arrays.equals(this.payload, o.payload));
- }
-
- @Override
- @SuppressFBWarnings("DE_MIGHT_IGNORE")
- public String toString() {
- String payloadString;
- try {
- payloadString = new String(payload, "UTF-8");
- } catch (UnsupportedEncodingException ex) {
- LOGGER.debug("UTF-8 charset not found on the JRE", ex);
- payloadString = "???";
- }
- return "Message(Id="+identifier+"; Token="+Utilities.encodeHex(deviceToken)+"; Payload="+payloadString+")";
- }
-}
diff --git a/src/main/java/com/notnoop/apns/PayloadBuilder.java b/src/main/java/com/notnoop/apns/PayloadBuilder.java
deleted file mode 100644
index 798c22a0..00000000
--- a/src/main/java/com/notnoop/apns/PayloadBuilder.java
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.notnoop.apns.internal.Utilities;
-
-/**
- * Represents a builder for constructing Payload requests, as
- * specified by Apple Push Notification Programming Guide.
- */
-public final class PayloadBuilder {
- private static final ObjectMapper mapper = new ObjectMapper();
-
- private final Map root;
- private final Map aps;
- private final Map customAlert;
-
- /**
- * Constructs a new instance of {@code PayloadBuilder}
- */
- PayloadBuilder() {
- root = new HashMap();
- aps = new HashMap();
- customAlert = new HashMap();
- }
-
- /**
- * Sets the alert body text, the text the appears to the user,
- * to the passed value
- *
- * @param alert the text to appear to the user
- * @return this
- */
- public PayloadBuilder alertBody(final String alert) {
- customAlert.put("body", alert);
- return this;
- }
-
- /**
- * Sets the alert title text, the text the appears to the user,
- * to the passed value.
- *
- * Used on iOS 8.2, iWatch and also Safari
- *
- * @param title the text to appear to the user
- * @return this
- */
- public PayloadBuilder alertTitle(final String title) {
- customAlert.put("title", title);
- return this;
- }
-
- /**
- * The key to a title string in the Localizable.strings file for the current localization.
- *
- * @param key the localizable message title key
- * @return this
- */
- public PayloadBuilder localizedTitleKey(final String key) {
- customAlert.put("title-loc-key", key);
- return this;
- }
-
- /**
- * Sets the arguments for the localizable title key.
- *
- * @param arguments the arguments to the localized alert message
- * @return this
- */
- public PayloadBuilder localizedTitleArguments(final Collection arguments) {
- customAlert.put("title-loc-args", arguments);
- return this;
- }
-
- /**
- * Sets the arguments for the localizable title key.
- *
- * @param arguments the arguments to the localized alert message
- * @return this
- */
- public PayloadBuilder localizedTitleArguments(final String... arguments) {
- return localizedTitleArguments(Arrays.asList(arguments));
- }
-
- /**
- * Sets the alert action text
- *
- * @param action The label of the action button
- * @return this
- */
- public PayloadBuilder alertAction(final String action) {
- customAlert.put("action", action);
- return this;
- }
-
- /**
- * Sets the "url-args" key that are paired with the placeholders
- * inside the urlFormatString value of your website.json file.
- * The order of the placeholders in the URL format string determines
- * the order of the values supplied by the url-args array.
- *
- * @param urlArgs the values to be paired with the placeholders inside
- * the urlFormatString value of your website.json file.
- * @return this
- */
- public PayloadBuilder urlArgs(final String... urlArgs){
- aps.put("url-args", urlArgs);
- return this;
- }
-
- /**
- * Sets the alert sound to be played.
- *
- * Passing {@code null} disables the notification sound.
- *
- * @param sound the file name or song name to be played
- * when receiving the notification
- * @return this
- */
- public PayloadBuilder sound(final String sound) {
- if (sound != null) {
- aps.put("sound", sound);
- } else {
- aps.remove("sound");
- }
- return this;
- }
-
- /**
- * Sets the category of the notification for iOS8 notification
- * actions. See 13 minutes into "What's new in iOS Notifications"
- *
- * Passing {@code null} removes the category.
- *
- * @param category the name of the category supplied to the app
- * when receiving the notification
- * @return this
- */
- public PayloadBuilder category(final String category) {
- if (category != null) {
- aps.put("category", category);
- } else {
- aps.remove("category");
- }
- return this;
- }
-
- /**
- * Sets the notification badge to be displayed next to the
- * application icon.
- *
- * The passed value is the value that should be displayed
- * (it will be added to the previous badge number), and
- * a badge of 0 clears the badge indicator.
- *
- * @param badge the badge number to be displayed
- * @return this
- */
- public PayloadBuilder badge(final int badge) {
- aps.put("badge", badge);
- return this;
- }
-
- /**
- * Requests clearing of the badge number next to the application
- * icon.
- *
- * This is an alias to {@code badge(0)}.
- *
- * @return this
- */
- public PayloadBuilder clearBadge() {
- return badge(0);
- }
-
- /**
- * Sets the value of action button (the right button to be
- * displayed). The default value is "View".
- *
- * The value can be either the simple String to be displayed or
- * a localizable key, and the iPhone will show the appropriate
- * localized message.
- *
- * A {@code null} actionKey indicates no additional button
- * is displayed, just the Cancel button.
- *
- * @param actionKey the title of the additional button
- * @return this
- */
- public PayloadBuilder actionKey(final String actionKey) {
- customAlert.put("action-loc-key", actionKey);
- return this;
- }
-
- /**
- * Set the notification view to display an action button.
- *
- * This is an alias to {@code actionKey(null)}
- *
- * @return this
- */
- public PayloadBuilder noActionButton() {
- return actionKey(null);
- }
-
- /**
- * Sets the notification type to be a 'newstand' notification.
- *
- * A Newstand Notification targets the Newstands app so that the app
- * updates the subscription info and content.
- *
- * @return this
- */
- public PayloadBuilder forNewsstand() {
- aps.put("content-available", 1);
- return this;
- }
-
- /**
- * With iOS7 it is possible to have the application wake up before the user opens the app.
- *
- * The same key-word can also be used to send 'silent' notifications. With these 'silent' notification
- * a different app delegate is being invoked, allowing the app to perform background tasks.
- *
- * @return this
- */
- public PayloadBuilder instantDeliveryOrSilentNotification() {
- aps.put("content-available", 1);
- return this;
- }
-
- /**
- * Set the notification localized key for the alert body
- * message.
- *
- * @param key the localizable message body key
- * @return this
- */
- public PayloadBuilder localizedKey(final String key) {
- customAlert.put("loc-key", key);
- return this;
- }
-
- /**
- * Sets the arguments for the alert message localizable message.
- *
- * The iPhone doesn't localize the arguments.
- *
- * @param arguments the arguments to the localized alert message
- * @return this
- */
- public PayloadBuilder localizedArguments(final Collection arguments) {
- customAlert.put("loc-args", arguments);
- return this;
- }
-
- /**
- * Sets the arguments for the alert message localizable message.
- *
- * The iPhone doesn't localize the arguments.
- *
- * @param arguments the arguments to the localized alert message
- * @return this
- */
- public PayloadBuilder localizedArguments(final String... arguments) {
- return localizedArguments(Arrays.asList(arguments));
- }
-
- /**
- * Sets the launch image file for the push notification
- *
- * @param launchImage the filename of the image file in the
- * application bundle.
- * @return this
- */
- public PayloadBuilder launchImage(final String launchImage) {
- customAlert.put("launch-image", launchImage);
- return this;
- }
-
- /**
- * Sets any application-specific custom fields. The values
- * are presented to the application and the iPhone doesn't
- * display them automatically.
- *
- * This can be used to pass specific values (urls, ids, etc) to
- * the application in addition to the notification message
- * itself.
- *
- * @param key the custom field name
- * @param value the custom field value
- * @return this
- */
- public PayloadBuilder customField(final String key, final Object value) {
- root.put(key, value);
- return this;
- }
-
- public PayloadBuilder mdm(final String s) {
- return customField("mdm", s);
- }
-
- /**
- * Set any application-specific custom fields. These values
- * are presented to the application and the iPhone doesn't
- * display them automatically.
- *
- * This method *adds* the custom fields in the map to the
- * payload, and subsequent calls add but doesn't reset the
- * custom fields.
- *
- * @param values the custom map
- * @return this
- */
- public PayloadBuilder customFields(final Map values) {
- root.putAll(values);
- return this;
- }
-
- /**
- * Returns the length of payload bytes once marshaled to bytes
- *
- * @return the length of the payload
- */
- public int length() {
- return copy().buildBytes().length;
- }
-
- /**
- * Returns true if the payload built so far is larger than
- * the size permitted by Apple (which is 2048 bytes).
- *
- * @return true if the result payload is too long
- */
- public boolean isTooLong() {
- return length() > Utilities.MAX_PAYLOAD_LENGTH;
- }
-
- /**
- * Shrinks the alert message body so that the resulting payload
- * message fits within the passed expected payload length.
- *
- * This method performs best-effort approach, and its behavior
- * is unspecified when handling alerts where the payload
- * without body is already longer than the permitted size, or
- * if the break occurs within word.
- *
- * @param payloadLength the expected max size of the payload
- * @return this
- */
- public PayloadBuilder resizeAlertBody(final int payloadLength) {
- return resizeAlertBody(payloadLength, "");
- }
-
- /**
- * Shrinks the alert message body so that the resulting payload
- * message fits within the passed expected payload length.
- *
- * This method performs best-effort approach, and its behavior
- * is unspecified when handling alerts where the payload
- * without body is already longer than the permitted size, or
- * if the break occurs within word.
- *
- * @param payloadLength the expected max size of the payload
- * @param postfix for the truncated body, e.g. "..."
- * @return this
- */
- public PayloadBuilder resizeAlertBody(final int payloadLength, final String postfix) {
- int currLength = length();
- if (currLength <= payloadLength) {
- return this;
- }
-
- // now we are sure that truncation is required
- String body = (String)customAlert.get("body");
-
- final int acceptableSize = Utilities.toUTF8Bytes(body).length
- - (currLength - payloadLength
- + Utilities.toUTF8Bytes(postfix).length);
- body = Utilities.truncateWhenUTF8(body, acceptableSize) + postfix;
-
- // set it back
- customAlert.put("body", body);
-
- // calculate the length again
- currLength = length();
-
- if(currLength > payloadLength) {
- // string is still too long, just remove the body as the body is
- // anyway not the cause OR the postfix might be too long
- customAlert.remove("body");
- }
-
- return this;
- }
-
- /**
- * Shrinks the alert message body so that the resulting payload
- * message fits within require Apple specification (2048 bytes).
- *
- * This method performs best-effort approach, and its behavior
- * is unspecified when handling alerts where the payload
- * without body is already longer than the permitted size, or
- * if the break occurs within word.
- *
- * @return this
- */
- public PayloadBuilder shrinkBody() {
- return shrinkBody("");
- }
-
- /**
- * Shrinks the alert message body so that the resulting payload
- * message fits within require Apple specification (2048 bytes).
- *
- * This method performs best-effort approach, and its behavior
- * is unspecified when handling alerts where the payload
- * without body is already longer than the permitted size, or
- * if the break occurs within word.
- *
- * @param postfix for the truncated body, e.g. "..."
- *
- * @return this
- */
- public PayloadBuilder shrinkBody(final String postfix) {
- return resizeAlertBody(Utilities.MAX_PAYLOAD_LENGTH, postfix);
- }
-
- /**
- * Returns the JSON String representation of the payload
- * according to Apple APNS specification
- *
- * @return the String representation as expected by Apple
- */
- public String build() {
- if (!root.containsKey("mdm")) {
- insertCustomAlert();
- root.put("aps", aps);
- }
- try {
- return mapper.writeValueAsString(root);
- } catch (final Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- private void insertCustomAlert() {
- switch (customAlert.size()) {
- case 0:
- aps.remove("alert");
- break;
- case 1:
- if (customAlert.containsKey("body")) {
- aps.put("alert", customAlert.get("body"));
- break;
- }
- // else follow through
- //$FALL-THROUGH$
- default:
- aps.put("alert", customAlert);
- }
- }
-
- /**
- * Returns the bytes representation of the payload according to
- * Apple APNS specification
- *
- * @return the bytes as expected by Apple
- */
- public byte[] buildBytes() {
- return Utilities.toUTF8Bytes(build());
- }
-
- @Override
- public String toString() {
- return build();
- }
-
- private PayloadBuilder(final Map root,
- final Map aps,
- final Map customAlert) {
- this.root = new HashMap(root);
- this.aps = new HashMap(aps);
- this.customAlert = new HashMap(customAlert);
- }
-
- /**
- * Returns a copy of this builder
- *
- * @return a copy of this builder
- */
- public PayloadBuilder copy() {
- return new PayloadBuilder(root, aps, customAlert);
- }
-
- /**
- * @return a new instance of Payload Builder
- */
- public static PayloadBuilder newPayload() {
- return new PayloadBuilder();
- }
-}
diff --git a/src/main/java/com/notnoop/apns/ReconnectPolicy.java b/src/main/java/com/notnoop/apns/ReconnectPolicy.java
deleted file mode 100644
index bff7dd96..00000000
--- a/src/main/java/com/notnoop/apns/ReconnectPolicy.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns;
-
-import com.notnoop.apns.internal.ReconnectPolicies;
-
-/**
- * Represents the reconnection policy for the library.
- *
- * Each object should be used exclusively for one
- * {@code ApnsService} only.
- */
-public interface ReconnectPolicy {
- /**
- * Returns {@code true} if the library should initiate a new
- * connection for sending the message.
- *
- * The library calls this method at every message push.
- *
- * @return true if the library should be reconnected
- */
- public boolean shouldReconnect();
-
- /**
- * Callback method to be called whenever the library
- * makes a new connection
- */
- public void reconnected();
-
- /**
- * Returns a deep copy of this reconnection policy, if needed.
- *
- * Subclasses may return this instance if the object is immutable.
- */
- public ReconnectPolicy copy();
-
- /**
- * Types of the library provided reconnection policies.
- *
- * This should capture most of the commonly used cases.
- */
- public enum Provided {
- /**
- * Only reconnect if absolutely needed, e.g. when the connection is dropped.
- *
- * Apple recommends using a persistent connection. This improves the latency of sending push notification messages.
- *
- * The down-side is that once the connection is closed ungracefully (e.g. because Apple server drops it), the library wouldn't
- * detect such failure and not warn against the messages sent after the drop before the detection.
- */
- NEVER {
- @Override
- public ReconnectPolicy newObject() {
- return new ReconnectPolicies.Never();
- }
- },
-
- /**
- * Makes a new connection if the current connection has lasted for more than half an hour.
- *
- * This is the recommended mode.
- *
- * This is the sweat-spot in my experiments between dropped connections while minimizing latency.
- */
- EVERY_HALF_HOUR {
- @Override
- public ReconnectPolicy newObject() {
- return new ReconnectPolicies.EveryHalfHour();
- }
- },
-
- /**
- * Makes a new connection for every message being sent.
- *
- * This option ensures that each message is actually
- * delivered to Apple.
- *
- * If you send a lot of messages though,
- * Apple may consider your requests to be a DoS attack.
- */
- EVERY_NOTIFICATION {
- @Override
- public ReconnectPolicy newObject() {
- return new ReconnectPolicies.Always();
- }
- };
-
- abstract ReconnectPolicy newObject();
- }
-}
diff --git a/src/main/java/com/notnoop/apns/SimpleApnsNotification.java b/src/main/java/com/notnoop/apns/SimpleApnsNotification.java
deleted file mode 100644
index 464c3bdf..00000000
--- a/src/main/java/com/notnoop/apns/SimpleApnsNotification.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns;
-
-import java.util.Arrays;
-
-import com.notnoop.apns.internal.Utilities;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import java.io.UnsupportedEncodingException;
-
-/**
- * Represents an APNS notification to be sent to Apple service. This is for legacy use only
- * and should not be used in new development.
- * https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/LegacyFormat.html
- *
- * This SimpleApnsNotification also only has limited error handling (by the APNS closing the connection
- * when a bad message was received) This prevents us from location the malformed notification.
- *
- * As push messages sent after a malformed notification are discarded by APNS messages will get lost
- * and not be delivered with the SimpleApnsNotification.
- *
- * @deprecated use EnhancedApnsNotification instead.
- */
-@SuppressWarnings("deprecation")
-@Deprecated
-public class SimpleApnsNotification implements ApnsNotification {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(SimpleApnsNotification.class);
- private final static byte COMMAND = 0;
- private final byte[] deviceToken;
- private final byte[] payload;
-
- /**
- * Constructs an instance of {@code ApnsNotification}.
- *
- * The message encodes the payload with a {@code UTF-8} encoding.
- *
- * @param dtoken The Hex of the device token of the destination phone
- * @param payload The payload message to be sent
- */
- public SimpleApnsNotification(String dtoken, String payload) {
- this.deviceToken = Utilities.decodeHex(dtoken);
- this.payload = Utilities.toUTF8Bytes(payload);
- }
-
- /**
- * Constructs an instance of {@code ApnsNotification}.
- *
- * @param dtoken The binary representation of the destination device token
- * @param payload The binary representation of the payload to be sent
- */
- public SimpleApnsNotification(byte[] dtoken, byte[] payload) {
- this.deviceToken = Utilities.copyOf(dtoken);
- this.payload = Utilities.copyOf(payload);
- }
-
- /**
- * Returns the binary representation of the device token.
- *
- */
- public byte[] getDeviceToken() {
- return Utilities.copyOf(deviceToken);
- }
-
- /**
- * Returns the binary representation of the payload.
- *
- */
- public byte[] getPayload() {
- return Utilities.copyOf(payload);
- }
-
- private byte[] marshall;
- /**
- * Returns the binary representation of the message as expected by the
- * APNS server.
- *
- * The returned array can be used to sent directly to the APNS server
- * (on the wire/socket) without any modification.
- */
- public byte[] marshall() {
- if (marshall == null)
- marshall = Utilities.marshall(COMMAND, deviceToken, payload);
- return marshall.clone();
- }
-
- /**
- * Returns the length of the message in bytes as it is encoded on the wire.
- *
- * Apple require the message to be of length 255 bytes or less.
- *
- * @return length of encoded message in bytes
- */
- public int length() {
- int length = 1 + 2 + deviceToken.length + 2 + payload.length;
- final int marshalledLength = marshall().length;
- assert marshalledLength == length;
- return length;
- }
-
- @Override
- public int hashCode() {
- return 21
- + 31 * Arrays.hashCode(deviceToken)
- + 31 * Arrays.hashCode(payload);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof SimpleApnsNotification))
- return false;
- SimpleApnsNotification o = (SimpleApnsNotification)obj;
- return Arrays.equals(this.deviceToken, o.deviceToken)
- && Arrays.equals(this.payload, o.payload);
- }
-
- public int getIdentifier() {
- return -1;
- }
-
- public int getExpiry() {
- return -1;
- }
-
- @Override
- @SuppressFBWarnings("DE_MIGHT_IGNORE")
- public String toString() {
- String payloadString;
- try {
- payloadString = new String(payload, "UTF-8");
- } catch (UnsupportedEncodingException ex) {
- LOGGER.debug("UTF-8 charset not found on the JRE", ex);
- payloadString = "???";
- }
- return "Message(Token="+Utilities.encodeHex(deviceToken)+"; Payload="+payloadString+")";
- }
-
-
-}
diff --git a/src/main/java/com/notnoop/apns/StartSendingApnsDelegate.java b/src/main/java/com/notnoop/apns/StartSendingApnsDelegate.java
deleted file mode 100644
index cf7d9577..00000000
--- a/src/main/java/com/notnoop/apns/StartSendingApnsDelegate.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns;
-
-/**
- * A delegate that also gets notified just before a notification is being delivered to the
- * Apple Server.
- */
-public interface StartSendingApnsDelegate extends ApnsDelegate {
-
- /**
- * Called when message is about to be sent to the Apple servers.
- *
- * @param message the notification that is about to be sent
- * @param resent whether the notification is being resent after an error
- */
- public void startSending(ApnsNotification message, boolean resent);
-
-}
diff --git a/src/main/java/com/notnoop/apns/internal/AbstractApnsService.java b/src/main/java/com/notnoop/apns/internal/AbstractApnsService.java
deleted file mode 100644
index 5f993649..00000000
--- a/src/main/java/com/notnoop/apns/internal/AbstractApnsService.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import com.notnoop.apns.ApnsNotification;
-import com.notnoop.apns.ApnsService;
-import com.notnoop.apns.EnhancedApnsNotification;
-import com.notnoop.exceptions.NetworkIOException;
-
-abstract class AbstractApnsService implements ApnsService {
- private ApnsFeedbackConnection feedback;
- private AtomicInteger c = new AtomicInteger();
-
- public AbstractApnsService(ApnsFeedbackConnection feedback) {
- this.feedback = feedback;
- }
-
- public EnhancedApnsNotification push(String deviceToken, String payload) throws NetworkIOException {
- EnhancedApnsNotification notification =
- new EnhancedApnsNotification(c.incrementAndGet(), EnhancedApnsNotification.MAXIMUM_EXPIRY, deviceToken, payload);
- push(notification);
- return notification;
- }
-
- public EnhancedApnsNotification push(String deviceToken, String payload, Date expiry) throws NetworkIOException {
- EnhancedApnsNotification notification =
- new EnhancedApnsNotification(c.incrementAndGet(), (int)(expiry.getTime() / 1000), deviceToken, payload);
- push(notification);
- return notification;
- }
-
- public EnhancedApnsNotification push(byte[] deviceToken, byte[] payload) throws NetworkIOException {
- EnhancedApnsNotification notification =
- new EnhancedApnsNotification(c.incrementAndGet(), EnhancedApnsNotification.MAXIMUM_EXPIRY, deviceToken, payload);
- push(notification);
- return notification;
- }
-
- public EnhancedApnsNotification push(byte[] deviceToken, byte[] payload, int expiry) throws NetworkIOException {
- EnhancedApnsNotification notification =
- new EnhancedApnsNotification(c.incrementAndGet(), expiry, deviceToken, payload);
- push(notification);
- return notification;
- }
-
- public Collection push(Collection deviceTokens, String payload) throws NetworkIOException {
- byte[] messageBytes = Utilities.toUTF8Bytes(payload);
- List notifications = new ArrayList(deviceTokens.size());
- for (String deviceToken : deviceTokens) {
- byte[] dtBytes = Utilities.decodeHex(deviceToken);
- EnhancedApnsNotification notification =
- new EnhancedApnsNotification(c.incrementAndGet(), EnhancedApnsNotification.MAXIMUM_EXPIRY, dtBytes, messageBytes);
- notifications.add(notification);
- push(notification);
- }
- return notifications;
- }
-
- public Collection push(Collection deviceTokens, String payload, Date expiry) throws NetworkIOException {
- byte[] messageBytes = Utilities.toUTF8Bytes(payload);
- List notifications = new ArrayList(deviceTokens.size());
- for (String deviceToken : deviceTokens) {
- byte[] dtBytes = Utilities.decodeHex(deviceToken);
- EnhancedApnsNotification notification =
- new EnhancedApnsNotification(c.incrementAndGet(), (int)(expiry.getTime() / 1000), dtBytes, messageBytes);
- notifications.add(notification);
- push(notification);
- }
- return notifications;
- }
-
- public Collection push(Collection deviceTokens, byte[] payload) throws NetworkIOException {
- List notifications = new ArrayList(deviceTokens.size());
- for (byte[] deviceToken : deviceTokens) {
- EnhancedApnsNotification notification =
- new EnhancedApnsNotification(c.incrementAndGet(), EnhancedApnsNotification.MAXIMUM_EXPIRY, deviceToken, payload);
- notifications.add(notification);
- push(notification);
- }
- return notifications;
- }
-
- public Collection push(Collection deviceTokens, byte[] payload, int expiry) throws NetworkIOException {
- List notifications = new ArrayList(deviceTokens.size());
- for (byte[] deviceToken : deviceTokens) {
- EnhancedApnsNotification notification =
- new EnhancedApnsNotification(c.incrementAndGet(), expiry, deviceToken, payload);
- notifications.add(notification);
- push(notification);
- }
- return notifications;
- }
-
- public abstract void push(ApnsNotification message) throws NetworkIOException;
-
- public Map getInactiveDevices() throws NetworkIOException {
- return feedback.getInactiveDevices();
- }
-}
diff --git a/src/main/java/com/notnoop/apns/internal/ApnsConnection.java b/src/main/java/com/notnoop/apns/internal/ApnsConnection.java
deleted file mode 100644
index 757a81b3..00000000
--- a/src/main/java/com/notnoop/apns/internal/ApnsConnection.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import java.io.Closeable;
-
-import com.notnoop.apns.ApnsNotification;
-import com.notnoop.exceptions.NetworkIOException;
-
-public interface ApnsConnection extends Closeable {
-
- //Default number of notifications to keep for error purposes
- public static final int DEFAULT_CACHE_LENGTH = 100;
-
- void sendMessage(ApnsNotification m) throws NetworkIOException;
-
- void testConnection() throws NetworkIOException;
-
- ApnsConnection copy();
-
- void setCacheLength(int cacheLength);
-
- int getCacheLength();
-}
diff --git a/src/main/java/com/notnoop/apns/internal/ApnsConnectionImpl.java b/src/main/java/com/notnoop/apns/internal/ApnsConnectionImpl.java
deleted file mode 100644
index 825aea3a..00000000
--- a/src/main/java/com/notnoop/apns/internal/ApnsConnectionImpl.java
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.InetSocketAddress;
-import java.net.Proxy;
-import java.net.Socket;
-import java.util.LinkedList;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.net.SocketFactory;
-import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.SSLSocketFactory;
-import com.notnoop.apns.ApnsDelegate;
-import com.notnoop.apns.StartSendingApnsDelegate;
-import com.notnoop.apns.ApnsNotification;
-import com.notnoop.apns.DeliveryError;
-import com.notnoop.apns.EnhancedApnsNotification;
-import com.notnoop.apns.ReconnectPolicy;
-import com.notnoop.exceptions.ApnsDeliveryErrorException;
-import com.notnoop.exceptions.NetworkIOException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ApnsConnectionImpl implements ApnsConnection {
-
- private static final Logger logger = LoggerFactory.getLogger(ApnsConnectionImpl.class);
-
- private final SocketFactory factory;
- private final String host;
- private final int port;
- private final int readTimeout;
- private final int connectTimeout;
- private final Proxy proxy;
- private final String proxyUsername;
- private final String proxyPassword;
- private final ReconnectPolicy reconnectPolicy;
- private final ApnsDelegate delegate;
- private int cacheLength;
- private final boolean errorDetection;
- private final ThreadFactory threadFactory;
- private final boolean autoAdjustCacheLength;
- private final ConcurrentLinkedQueue cachedNotifications, notificationsBuffer;
- private Socket socket;
- private final AtomicInteger threadId = new AtomicInteger(0);
-
- public ApnsConnectionImpl(SocketFactory factory, String host, int port) {
- this(factory, host, port, new ReconnectPolicies.Never(), ApnsDelegate.EMPTY);
- }
-
- private ApnsConnectionImpl(SocketFactory factory, String host, int port, ReconnectPolicy reconnectPolicy, ApnsDelegate delegate) {
- this(factory, host, port, null, null, null, reconnectPolicy, delegate);
- }
-
- private ApnsConnectionImpl(SocketFactory factory, String host, int port, Proxy proxy, String proxyUsername, String proxyPassword,
- ReconnectPolicy reconnectPolicy, ApnsDelegate delegate) {
- this(factory, host, port, proxy, proxyUsername, proxyPassword, reconnectPolicy, delegate, false, null,
- ApnsConnection.DEFAULT_CACHE_LENGTH, true, 0, 0);
- }
-
- public ApnsConnectionImpl(SocketFactory factory, String host, int port, Proxy proxy, String proxyUsername, String proxyPassword,
- ReconnectPolicy reconnectPolicy, ApnsDelegate delegate, boolean errorDetection, ThreadFactory tf, int cacheLength,
- boolean autoAdjustCacheLength, int readTimeout, int connectTimeout) {
- this.factory = factory;
- this.host = host;
- this.port = port;
- this.reconnectPolicy = reconnectPolicy;
- this.delegate = delegate == null ? ApnsDelegate.EMPTY : delegate;
- this.proxy = proxy;
- this.errorDetection = errorDetection;
- this.threadFactory = tf == null ? defaultThreadFactory() : tf;
- this.cacheLength = cacheLength;
- this.autoAdjustCacheLength = autoAdjustCacheLength;
- this.readTimeout = readTimeout;
- this.connectTimeout = connectTimeout;
- this.proxyUsername = proxyUsername;
- this.proxyPassword = proxyPassword;
- cachedNotifications = new ConcurrentLinkedQueue();
- notificationsBuffer = new ConcurrentLinkedQueue();
- }
-
- private ThreadFactory defaultThreadFactory() {
- return new ThreadFactory() {
- ThreadFactory wrapped = Executors.defaultThreadFactory();
- @Override
- public Thread newThread( Runnable r )
- {
- Thread result = wrapped.newThread(r);
- result.setName("MonitoringThread-"+threadId.incrementAndGet());
- result.setDaemon(true);
- return result;
- }
- };
- }
-
- public synchronized void close() {
- Utilities.close(socket);
- }
-
- private void monitorSocket(final Socket socketToMonitor) {
- logger.debug("Launching Monitoring Thread for socket {}", socketToMonitor);
-
- Thread t = threadFactory.newThread(new Runnable() {
- final static int EXPECTED_SIZE = 6;
-
- @SuppressWarnings("InfiniteLoopStatement")
- @Override
- public void run() {
- logger.debug("Started monitoring thread");
- try {
- InputStream in;
- try {
- in = socketToMonitor.getInputStream();
- } catch (IOException ioe) {
- logger.warn("The value of socket is null", ioe);
- in = null;
- }
-
- byte[] bytes = new byte[EXPECTED_SIZE];
- while (in != null && readPacket(in, bytes)) {
- logger.debug("Error-response packet {}", Utilities.encodeHex(bytes));
- // Quickly close socket, so we won't ever try to send push notifications
- // using the defective socket.
- Utilities.close(socketToMonitor);
-
- int command = bytes[0] & 0xFF;
- if (command != 8) {
- throw new IOException("Unexpected command byte " + command);
- }
- int statusCode = bytes[1] & 0xFF;
- DeliveryError e = DeliveryError.ofCode(statusCode);
-
- int id = Utilities.parseBytes(bytes[2], bytes[3], bytes[4], bytes[5]);
-
- logger.debug("Closed connection cause={}; id={}", e, id);
- delegate.connectionClosed(e, id);
-
- Queue tempCache = new LinkedList();
- ApnsNotification notification = null;
- boolean foundNotification = false;
-
- while (!cachedNotifications.isEmpty()) {
- notification = cachedNotifications.poll();
- logger.debug("Candidate for removal, message id {}", notification.getIdentifier());
-
- if (notification.getIdentifier() == id) {
- logger.debug("Bad message found {}", notification.getIdentifier());
- foundNotification = true;
- break;
- }
- tempCache.add(notification);
- }
-
- if (foundNotification) {
- logger.debug("delegate.messageSendFailed, message id {}", notification.getIdentifier());
- delegate.messageSendFailed(notification, new ApnsDeliveryErrorException(e));
- } else {
- cachedNotifications.addAll(tempCache);
- int resendSize = tempCache.size();
- logger.warn("Received error for message that wasn't in the cache...");
- if (autoAdjustCacheLength) {
- cacheLength = cacheLength + (resendSize / 2);
- delegate.cacheLengthExceeded(cacheLength);
- }
- logger.debug("delegate.messageSendFailed, unknown id");
- delegate.messageSendFailed(null, new ApnsDeliveryErrorException(e));
- }
-
- int resendSize = 0;
-
- while (!cachedNotifications.isEmpty()) {
-
- resendSize++;
- final ApnsNotification resendNotification = cachedNotifications.poll();
- logger.debug("Queuing for resend {}", resendNotification.getIdentifier());
- notificationsBuffer.add(resendNotification);
- }
- logger.debug("resending {} notifications", resendSize);
- delegate.notificationsResent(resendSize);
- }
- logger.debug("Monitoring input stream closed by EOF");
-
- } catch (IOException e) {
- // An exception when reading the error code is non-critical, it will cause another retry
- // sending the message. Other than providing a more stable network connection to the APNS
- // server we can't do much about it - so let's not spam the application's error log.
- logger.info("Exception while waiting for error code", e);
- delegate.connectionClosed(DeliveryError.UNKNOWN, -1);
- } finally {
- Utilities.close(socketToMonitor);
- drainBuffer();
- }
- }
-
- /**
- * Read a packet like in.readFully(bytes) does - but do not throw an exception and return false if nothing
- * could be read at all.
- * @param in the input stream
- * @param bytes the array to be filled with data
- * @return true if a packet as been read, false if the stream was at EOF right at the beginning.
- * @throws IOException When a problem occurs, especially EOFException when there's an EOF in the middle of the packet.
- */
- private boolean readPacket(final InputStream in, final byte[] bytes) throws IOException {
- final int len = bytes.length;
- int n = 0;
- while (n < len) {
- try {
- int count = in.read(bytes, n, len - n);
- if (count < 0) {
- throw new EOFException("EOF after reading "+n+" bytes of new packet.");
- }
- n += count;
- } catch (IOException ioe) {
- if (n == 0)
- return false;
- throw new IOException("Error after reading "+n+" bytes of packet", ioe);
- }
- }
- return true;
- }
- });
- t.start();
- }
-
- private synchronized Socket getOrCreateSocket(boolean resend) throws NetworkIOException {
- if (reconnectPolicy.shouldReconnect()) {
- logger.debug("Reconnecting due to reconnectPolicy dictating it");
- Utilities.close(socket);
- socket = null;
- }
-
- if (socket == null || socket.isClosed()) {
- try {
- if (proxy == null) {
- socket = factory.createSocket(host, port);
- logger.debug("Connected new socket {}", socket);
- } else if (proxy.type() == Proxy.Type.HTTP) {
- TlsTunnelBuilder tunnelBuilder = new TlsTunnelBuilder();
- socket = tunnelBuilder.build((SSLSocketFactory) factory, proxy, proxyUsername, proxyPassword, host, port);
- logger.debug("Connected new socket through http tunnel {}", socket);
- } else {
- boolean success = false;
- Socket proxySocket = null;
- try {
- proxySocket = new Socket(proxy);
- proxySocket.connect(new InetSocketAddress(host, port), connectTimeout);
- socket = ((SSLSocketFactory) factory).createSocket(proxySocket, host, port, false);
- success = true;
- } finally {
- if (!success) {
- Utilities.close(proxySocket);
- }
- }
- logger.debug("Connected new socket through socks tunnel {}", socket);
- }
-
- socket.setSoTimeout(readTimeout);
- socket.setKeepAlive(true);
-
- if (errorDetection) {
- monitorSocket(socket);
- }
-
- reconnectPolicy.reconnected();
- logger.debug("Made a new connection to APNS");
- } catch (IOException e) {
- logger.error("Couldn't connect to APNS server", e);
- // indicate to clients whether this is a resend or initial send
- throw new NetworkIOException(e, resend);
- }
- }
- return socket;
- }
-
- int DELAY_IN_MS = 1000;
- private static final int RETRIES = 3;
-
- public synchronized void sendMessage(ApnsNotification m) throws NetworkIOException {
- sendMessage(m, false);
- drainBuffer();
- }
-
- private synchronized void sendMessage(ApnsNotification m, boolean fromBuffer) throws NetworkIOException {
- logger.debug("sendMessage {} fromBuffer: {}", m, fromBuffer);
-
- if (delegate instanceof StartSendingApnsDelegate) {
- ((StartSendingApnsDelegate) delegate).startSending(m, fromBuffer);
- }
-
- int attempts = 0;
- while (true) {
- try {
- attempts++;
- Socket socket = getOrCreateSocket(fromBuffer);
- socket.getOutputStream().write(m.marshall());
- socket.getOutputStream().flush();
- cacheNotification(m);
-
- delegate.messageSent(m, fromBuffer);
-
- //logger.debug("Message \"{}\" sent", m);
- attempts = 0;
- break;
- } catch (SSLHandshakeException e) {
- // No use retrying this, it's dead Jim
- throw new NetworkIOException(e);
- } catch (IOException e) {
- Utilities.close(socket);
- if (attempts >= RETRIES) {
- logger.error("Couldn't send message after " + RETRIES + " retries." + m, e);
- delegate.messageSendFailed(m, e);
- Utilities.wrapAndThrowAsRuntimeException(e);
- }
- // The first failure might be due to closed connection (which in turn might be caused by
- // a message containing a bad token), so don't delay for the first retry.
- //
- // Additionally we don't want to spam the log file in this case, only after the second retry
- // which uses the delay.
-
- if (attempts != 1) {
- logger.info("Failed to send message " + m + "... trying again after delay", e);
- Utilities.sleep(DELAY_IN_MS);
- }
- }
- }
- }
-
- private synchronized void drainBuffer() {
- logger.debug("draining buffer");
- while (!notificationsBuffer.isEmpty()) {
- final ApnsNotification notification = notificationsBuffer.poll();
- try {
- sendMessage(notification, true);
- }
- catch (NetworkIOException ex) {
- // at this point we are retrying the submission of messages but failing to connect to APNS, therefore
- // notify the client of this
- delegate.messageSendFailed(notification, ex);
- }
- }
- }
-
- private void cacheNotification(ApnsNotification notification) {
- cachedNotifications.add(notification);
- while (cachedNotifications.size() > cacheLength) {
- cachedNotifications.poll();
- logger.debug("Removing notification from cache " + notification);
- }
- }
-
- public ApnsConnectionImpl copy() {
- return new ApnsConnectionImpl(factory, host, port, proxy, proxyUsername, proxyPassword, reconnectPolicy.copy(), delegate,
- errorDetection, threadFactory, cacheLength, autoAdjustCacheLength, readTimeout, connectTimeout);
- }
-
- public void testConnection() throws NetworkIOException {
- ApnsConnectionImpl testConnection = null;
- try {
- testConnection =
- new ApnsConnectionImpl(factory, host, port, proxy, proxyUsername, proxyPassword, reconnectPolicy.copy(), delegate);
- final ApnsNotification notification = new EnhancedApnsNotification(0, 0, new byte[]{0}, new byte[]{0});
- testConnection.sendMessage(notification);
- } finally {
- if (testConnection != null) {
- testConnection.close();
- }
- }
- }
-
- public void setCacheLength(int cacheLength) {
- this.cacheLength = cacheLength;
- }
-
- public int getCacheLength() {
- return cacheLength;
- }
-}
diff --git a/src/main/java/com/notnoop/apns/internal/ApnsFeedbackConnection.java b/src/main/java/com/notnoop/apns/internal/ApnsFeedbackConnection.java
deleted file mode 100644
index 26db2086..00000000
--- a/src/main/java/com/notnoop/apns/internal/ApnsFeedbackConnection.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.InetSocketAddress;
-import java.net.Proxy;
-import java.net.Socket;
-import java.util.Date;
-import java.util.Map;
-import javax.net.SocketFactory;
-import javax.net.ssl.SSLSocketFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import com.notnoop.exceptions.NetworkIOException;
-
-public class ApnsFeedbackConnection {
- private static final Logger logger = LoggerFactory.getLogger(ApnsFeedbackConnection.class);
-
- private final SocketFactory factory;
- private final String host;
- private final int port;
- private final Proxy proxy;
- private final int readTimeout;
- private final int connectTimeout;
- private final String proxyUsername;
- private final String proxyPassword;
-
- public ApnsFeedbackConnection(final SocketFactory factory, final String host, final int port) {
- this(factory, host, port, null, 0, 0, null, null);
- }
-
- public ApnsFeedbackConnection(final SocketFactory factory, final String host, final int port,
- final Proxy proxy, int readTimeout, int connectTimeout, final String proxyUsername, final String proxyPassword) {
- this.factory = factory;
- this.host = host;
- this.port = port;
- this.proxy = proxy;
- this.readTimeout = readTimeout;
- this.connectTimeout = connectTimeout;
- this.proxyUsername = proxyUsername;
- this.proxyPassword = proxyPassword;
- }
-
- int DELAY_IN_MS = 1000;
- private static final int RETRIES = 3;
-
- public Map getInactiveDevices() throws NetworkIOException {
- int attempts = 0;
- while (true) {
- try {
- attempts++;
- final Map result = getInactiveDevicesImpl();
-
- attempts = 0;
- return result;
- } catch (final Exception e) {
- logger.warn("Failed to retrieve invalid devices", e);
- if (attempts >= RETRIES) {
- logger.error("Couldn't get feedback connection", e);
- Utilities.wrapAndThrowAsRuntimeException(e);
- }
- Utilities.sleep(DELAY_IN_MS);
- }
- }
- }
-
- public Map getInactiveDevicesImpl() throws IOException {
- Socket proxySocket = null;
- Socket socket = null;
- try {
- if (proxy == null) {
- socket = factory.createSocket(host, port);
- } else if (proxy.type() == Proxy.Type.HTTP) {
- TlsTunnelBuilder tunnelBuilder = new TlsTunnelBuilder();
- socket = tunnelBuilder.build((SSLSocketFactory) factory, proxy, proxyUsername, proxyPassword, host, port);
- } else {
- proxySocket = new Socket(proxy);
- proxySocket.connect(new InetSocketAddress(host, port), connectTimeout);
- socket = ((SSLSocketFactory) factory).createSocket(proxySocket, host, port, false);
- }
- socket.setSoTimeout(readTimeout);
- socket.setKeepAlive(true);
- final InputStream stream = socket.getInputStream();
- return Utilities.parseFeedbackStream(stream);
- } finally {
- Utilities.close(socket);
- Utilities.close(proxySocket);
- }
- }
-
-}
diff --git a/src/main/java/com/notnoop/apns/internal/ApnsPooledConnection.java b/src/main/java/com/notnoop/apns/internal/ApnsPooledConnection.java
deleted file mode 100644
index e27d1702..00000000
--- a/src/main/java/com/notnoop/apns/internal/ApnsPooledConnection.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import java.util.concurrent.*;
-import com.notnoop.apns.ApnsNotification;
-import com.notnoop.exceptions.NetworkIOException;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ApnsPooledConnection implements ApnsConnection {
- private static final Logger logger = LoggerFactory.getLogger(ApnsPooledConnection.class);
-
- private final ApnsConnection prototype;
- private final int max;
-
- private final ExecutorService executors;
- private final ConcurrentLinkedQueue prototypes;
-
- public ApnsPooledConnection(ApnsConnection prototype, int max) {
- this(prototype, max, Executors.newFixedThreadPool(max));
- }
-
- public ApnsPooledConnection(ApnsConnection prototype, int max, ExecutorService executors) {
- this.prototype = prototype;
- this.max = max;
-
- this.executors = executors;
- this.prototypes = new ConcurrentLinkedQueue();
- }
-
- private final ThreadLocal uniquePrototype =
- new ThreadLocal() {
- protected ApnsConnection initialValue() {
- ApnsConnection newCopy = prototype.copy();
- prototypes.add(newCopy);
- return newCopy;
- }
- };
-
- public void sendMessage(final ApnsNotification m) throws NetworkIOException {
- Future future = executors.submit(new Callable() {
- public Void call() throws Exception {
- uniquePrototype.get().sendMessage(m);
- return null;
- }
- });
- try {
- future.get();
- } catch (InterruptedException ie) {
- Thread.currentThread().interrupt();
- } catch (ExecutionException ee) {
- if (ee.getCause() instanceof NetworkIOException) {
- throw (NetworkIOException) ee.getCause();
- }
- }
- }
-
- public ApnsConnection copy() {
- // TODO: Should copy executor properly.... What should copy do
- // really?!
- return new ApnsPooledConnection(prototype, max);
- }
-
- public void close() {
- executors.shutdown();
- try {
- executors.awaitTermination(10, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- logger.warn("pool termination interrupted", e);
- }
- for (ApnsConnection conn : prototypes) {
- Utilities.close(conn);
- }
- Utilities.close(prototype);
- }
-
- public void testConnection() {
- prototype.testConnection();
- }
-
- public synchronized void setCacheLength(int cacheLength) {
- for (ApnsConnection conn : prototypes) {
- conn.setCacheLength(cacheLength);
- }
- }
-
- @SuppressFBWarnings(value = "UG_SYNC_SET_UNSYNC_GET", justification = "prototypes is a MT-safe container")
- public int getCacheLength() {
- return prototypes.peek().getCacheLength();
- }
-}
diff --git a/src/main/java/com/notnoop/apns/internal/ApnsServiceImpl.java b/src/main/java/com/notnoop/apns/internal/ApnsServiceImpl.java
deleted file mode 100644
index 387f5a8f..00000000
--- a/src/main/java/com/notnoop/apns/internal/ApnsServiceImpl.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import com.notnoop.apns.ApnsNotification;
-import com.notnoop.exceptions.NetworkIOException;
-
-public class ApnsServiceImpl extends AbstractApnsService {
- private ApnsConnection connection;
-
- public ApnsServiceImpl(ApnsConnection connection, ApnsFeedbackConnection feedback) {
- super(feedback);
- this.connection = connection;
- }
-
- @Override
- public void push(ApnsNotification msg) throws NetworkIOException {
- connection.sendMessage(msg);
- }
-
- public void start() {
- }
-
- public void stop() {
- Utilities.close(connection);
- }
-
- public void testConnection() {
- connection.testConnection();
- }
-}
diff --git a/src/main/java/com/notnoop/apns/internal/BatchApnsService.java b/src/main/java/com/notnoop/apns/internal/BatchApnsService.java
deleted file mode 100644
index d7dcbefb..00000000
--- a/src/main/java/com/notnoop/apns/internal/BatchApnsService.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import static java.util.concurrent.Executors.defaultThreadFactory;
-
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.TimeUnit;
-
-import com.notnoop.apns.ApnsNotification;
-import com.notnoop.exceptions.NetworkIOException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class BatchApnsService extends AbstractApnsService {
-
- private static final Logger logger = LoggerFactory.getLogger(BatchApnsService.class);
-
- /**
- * How many seconds to wait for more messages before batch is send.
- * Each message reset the wait time
- *
- * @see #maxBatchWaitTimeInSec
- */
- private int batchWaitTimeInSec = 5;
-
- /**
- * How many seconds can be batch delayed before execution.
- * This time is not exact amount after which the batch will run its roughly the time
- */
- private int maxBatchWaitTimeInSec = 10;
-
- private long firstMessageArrivedTime;
-
- private ApnsConnection prototype;
-
- private Queue batch = new ConcurrentLinkedQueue();
-
- private ScheduledExecutorService scheduleService;
- private ScheduledFuture> taskFuture;
-
- private Runnable batchRunner = new SendMessagesBatch();
-
- public BatchApnsService(ApnsConnection prototype, ApnsFeedbackConnection feedback, int batchWaitTimeInSec, int maxBachWaitTimeInSec, ThreadFactory tf) {
- this(prototype, feedback, batchWaitTimeInSec, maxBachWaitTimeInSec,
- new ScheduledThreadPoolExecutor(1,
- tf != null ? tf : defaultThreadFactory()));
- }
-
- public BatchApnsService(ApnsConnection prototype, ApnsFeedbackConnection feedback, int batchWaitTimeInSec, int maxBachWaitTimeInSec, ScheduledExecutorService executor) {
- super(feedback);
- this.prototype = prototype;
- this.batchWaitTimeInSec = batchWaitTimeInSec;
- this.maxBatchWaitTimeInSec = maxBachWaitTimeInSec;
- this.scheduleService = executor != null ? executor : new ScheduledThreadPoolExecutor(1, defaultThreadFactory());
- }
-
- public void start() {
- // no code
- }
-
- public void stop() {
- Utilities.close(prototype);
- if (taskFuture != null) {
- taskFuture.cancel(true);
- }
- scheduleService.shutdownNow();
- }
-
- public void testConnection() throws NetworkIOException {
- prototype.testConnection();
- }
-
- @Override
- public void push(ApnsNotification message) throws NetworkIOException {
- if (batch.isEmpty()) {
- firstMessageArrivedTime = System.nanoTime();
- }
-
- long sinceFirstMessageSec = (System.nanoTime() - firstMessageArrivedTime) / 1000 / 1000 / 1000;
-
- if (taskFuture != null && sinceFirstMessageSec < maxBatchWaitTimeInSec) {
- taskFuture.cancel(false);
- }
-
- batch.add(message);
-
- if (taskFuture == null || taskFuture.isDone()) {
- taskFuture = scheduleService.schedule(batchRunner, batchWaitTimeInSec, TimeUnit.SECONDS);
- }
- }
-
- class SendMessagesBatch implements Runnable {
- public void run() {
- ApnsConnection newConnection = prototype.copy();
- try {
- ApnsNotification msg;
- while ((msg = batch.poll()) != null) {
- try {
- newConnection.sendMessage(msg);
- } catch (NetworkIOException e) {
- logger.warn("Network exception sending message msg "+ msg.getIdentifier(), e);
- }
- }
- } finally {
- Utilities.close(newConnection);
- }
- }
- }
-}
diff --git a/src/main/java/com/notnoop/apns/internal/QueuedApnsService.java b/src/main/java/com/notnoop/apns/internal/QueuedApnsService.java
deleted file mode 100644
index 21cc8202..00000000
--- a/src/main/java/com/notnoop/apns/internal/QueuedApnsService.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import java.util.Date;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.Executors;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ThreadFactory;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.notnoop.apns.ApnsNotification;
-import com.notnoop.apns.ApnsService;
-import com.notnoop.exceptions.NetworkIOException;
-
-public class QueuedApnsService extends AbstractApnsService {
-
- private static final Logger logger = LoggerFactory.getLogger(QueuedApnsService.class);
-
- private ApnsService service;
- private BlockingQueue queue;
- private AtomicBoolean started = new AtomicBoolean(false);
-
- public QueuedApnsService(ApnsService service) {
- this(service, null);
- }
-
- public QueuedApnsService(ApnsService service, final ThreadFactory tf) {
- super(null);
- this.service = service;
- this.queue = new LinkedBlockingQueue();
- this.threadFactory = tf == null ? Executors.defaultThreadFactory() : tf;
- this.thread = null;
- }
-
- @Override
- public void push(ApnsNotification msg) {
- if (!started.get()) {
- throw new IllegalStateException("service hasn't be started or was closed");
- }
- queue.add(msg);
- }
-
- private final ThreadFactory threadFactory;
- private Thread thread;
- private volatile boolean shouldContinue;
-
- public void start() {
- if (started.getAndSet(true)) {
- // I prefer if we throw a runtime IllegalStateException here,
- // but I want to maintain semantic backward compatibility.
- // So it is returning immediately here
- return;
- }
-
- service.start();
- shouldContinue = true;
- thread = threadFactory.newThread(new Runnable() {
- public void run() {
- while (shouldContinue) {
- try {
- ApnsNotification msg = queue.take();
- service.push(msg);
- } catch (InterruptedException e) {
- // ignore
- } catch (NetworkIOException e) {
- // ignore: failed connect...
- } catch (Exception e) {
- // weird if we reached here - something wrong is happening, but we shouldn't stop the service anyway!
- logger.warn("Unexpected message caught... Shouldn't be here", e);
- }
- }
- }
- });
- thread.start();
- }
-
- public void stop() {
- started.set(false);
- shouldContinue = false;
- thread.interrupt();
- service.stop();
- }
-
- @Override
- public Map getInactiveDevices() throws NetworkIOException {
- return service.getInactiveDevices();
- }
-
- public void testConnection() throws NetworkIOException {
- service.testConnection();
- }
-
-}
diff --git a/src/main/java/com/notnoop/apns/internal/ReconnectPolicies.java b/src/main/java/com/notnoop/apns/internal/ReconnectPolicies.java
deleted file mode 100644
index b6a70eb6..00000000
--- a/src/main/java/com/notnoop/apns/internal/ReconnectPolicies.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import com.notnoop.apns.ReconnectPolicy;
-
-public final class ReconnectPolicies {
-
- public static class Never implements ReconnectPolicy {
-
- public boolean shouldReconnect() { return false; }
- public void reconnected() { }
- public Never copy() { return this; }
- }
-
- public static class Always implements ReconnectPolicy {
- public boolean shouldReconnect() { return true; }
- public void reconnected() { }
- public Always copy() { return this; }
- }
-
- public static class EveryHalfHour implements ReconnectPolicy {
- private static final long PERIOD = 30 * 60 * 1000;
-
- private long lastRunning = System.currentTimeMillis();
-
- public boolean shouldReconnect() {
- return System.currentTimeMillis() - lastRunning > PERIOD;
- }
-
- public void reconnected() {
- lastRunning = System.currentTimeMillis();
- }
-
- public EveryHalfHour copy() {
- return new EveryHalfHour();
- }
- }
-}
diff --git a/src/main/java/com/notnoop/apns/internal/SSLContextBuilder.java b/src/main/java/com/notnoop/apns/internal/SSLContextBuilder.java
deleted file mode 100644
index 5175bfd1..00000000
--- a/src/main/java/com/notnoop/apns/internal/SSLContextBuilder.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import com.notnoop.exceptions.InvalidSSLConfig;
-
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.GeneralSecurityException;
-import java.security.Key;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-
-public class SSLContextBuilder {
- private String algorithm = "sunx509";
- private KeyManagerFactory keyManagerFactory;
- private TrustManager[] trustManagers;
-
- public SSLContextBuilder withAlgorithm(String algorithm) {
- this.algorithm = algorithm;
- return this;
- }
-
- public SSLContextBuilder withDefaultTrustKeyStore() throws InvalidSSLConfig {
- try {
- TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(algorithm);
- trustManagerFactory.init((KeyStore)null);
- trustManagers = trustManagerFactory.getTrustManagers();
- return this;
- } catch (GeneralSecurityException e) {
- throw new InvalidSSLConfig(e);
- }
- }
-
- public SSLContextBuilder withTrustKeyStore(InputStream keyStoreStream, String keyStorePassword, String keyStoreType) throws InvalidSSLConfig {
- try {
- final KeyStore ks = KeyStore.getInstance(keyStoreType);
- ks.load(keyStoreStream, keyStorePassword.toCharArray());
- return withTrustKeyStore(ks, keyStorePassword);
- } catch (GeneralSecurityException e) {
- throw new InvalidSSLConfig(e);
- } catch (IOException e) {
- throw new InvalidSSLConfig(e);
- }
-
- }
- public SSLContextBuilder withTrustKeyStore(KeyStore keyStore, String keyStorePassword) throws InvalidSSLConfig {
- try {
- TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(algorithm);
- trustManagerFactory.init(keyStore);
- trustManagers = trustManagerFactory.getTrustManagers();
- return this;
- } catch (GeneralSecurityException e) {
- throw new InvalidSSLConfig(e);
- }
- }
-
- public SSLContextBuilder withTrustManager(TrustManager trustManager) {
- trustManagers = new TrustManager[] { trustManager };
- return this;
- }
-
- public SSLContextBuilder withCertificateKeyStore(InputStream keyStoreStream, String keyStorePassword, String keyStoreType) throws InvalidSSLConfig {
- try {
- final KeyStore ks = KeyStore.getInstance(keyStoreType);
- ks.load(keyStoreStream, keyStorePassword.toCharArray());
- return withCertificateKeyStore(ks, keyStorePassword);
- } catch (GeneralSecurityException e) {
- throw new InvalidSSLConfig(e);
- } catch (IOException e) {
- throw new InvalidSSLConfig(e);
- }
- }
-
- public SSLContextBuilder withCertificateKeyStore(InputStream keyStoreStream, String keyStorePassword, String keyStoreType, String keyAlias) throws InvalidSSLConfig {
- try {
- final KeyStore ks = KeyStore.getInstance(keyStoreType);
- ks.load(keyStoreStream, keyStorePassword.toCharArray());
- return withCertificateKeyStore(ks, keyStorePassword, keyAlias);
- } catch (GeneralSecurityException e) {
- throw new InvalidSSLConfig(e);
- } catch (IOException e) {
- throw new InvalidSSLConfig(e);
- }
- }
-
- public SSLContextBuilder withCertificateKeyStore(KeyStore keyStore, String keyStorePassword) throws InvalidSSLConfig {
- try {
- keyManagerFactory = KeyManagerFactory.getInstance(algorithm);
- keyManagerFactory.init(keyStore, keyStorePassword.toCharArray());
- return this;
- } catch (GeneralSecurityException e) {
- throw new InvalidSSLConfig(e);
- }
- }
-
- public SSLContextBuilder withCertificateKeyStore(KeyStore keyStore, String keyStorePassword, String keyAlias) throws InvalidSSLConfig {
- try {
- if (!keyStore.containsAlias(keyAlias)) {
- throw new InvalidSSLConfig("No key with alias " + keyAlias);
- }
- KeyStore singleKeyKeyStore = getKeyStoreWithSingleKey(keyStore, keyStorePassword, keyAlias);
- return withCertificateKeyStore(singleKeyKeyStore, keyStorePassword);
- } catch (GeneralSecurityException e) {
- throw new InvalidSSLConfig(e);
- } catch (IOException e) {
- throw new InvalidSSLConfig(e);
- }
- }
-
- /*
- * Workaround for keystores containing multiple keys. Java will take the first key that matches
- * and this way we can still offer configuration for a keystore with multiple keys and a selection
- * based on alias. Also much easier than making a subclass of a KeyManagerFactory
- */
- private KeyStore getKeyStoreWithSingleKey(KeyStore keyStore, String keyStorePassword, String keyAlias)
- throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException {
- KeyStore singleKeyKeyStore = KeyStore.getInstance(keyStore.getType(), keyStore.getProvider());
- final char[] password = keyStorePassword.toCharArray();
- singleKeyKeyStore.load(null, password);
- Key key = keyStore.getKey(keyAlias, password);
- Certificate[] chain = keyStore.getCertificateChain(keyAlias);
- singleKeyKeyStore.setKeyEntry(keyAlias, key, password, chain);
- return singleKeyKeyStore;
- }
-
- public SSLContext build() throws InvalidSSLConfig {
- if (keyManagerFactory == null) {
- throw new InvalidSSLConfig("Missing KeyManagerFactory");
- }
-
- if (trustManagers == null) {
- throw new InvalidSSLConfig("Missing TrustManagers");
- }
-
- try {
- final SSLContext sslContext = SSLContext.getInstance("TLS");
- sslContext.init(keyManagerFactory.getKeyManagers(), trustManagers, null);
- return sslContext;
- } catch (GeneralSecurityException e) {
- throw new InvalidSSLConfig(e);
- }
- }
-}
diff --git a/src/main/java/com/notnoop/apns/internal/TlsTunnelBuilder.java b/src/main/java/com/notnoop/apns/internal/TlsTunnelBuilder.java
deleted file mode 100644
index 5e0d68cf..00000000
--- a/src/main/java/com/notnoop/apns/internal/TlsTunnelBuilder.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.ProtocolException;
-import java.net.Proxy;
-import java.net.Socket;
-import javax.net.ssl.SSLSocketFactory;
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import org.apache.commons.httpclient.ConnectMethod;
-import org.apache.commons.httpclient.NTCredentials;
-import org.apache.commons.httpclient.ProxyClient;
-import org.apache.commons.httpclient.UsernamePasswordCredentials;
-import org.apache.commons.httpclient.auth.AuthScope;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Establishes a TLS connection using an HTTP proxy. See RFC 2817 5.2. This class does
- * not support proxies requiring a "Proxy-Authorization" header.
- */
-public final class TlsTunnelBuilder {
-
- private static final Logger logger = LoggerFactory.getLogger(TlsTunnelBuilder.class);
-
- public Socket build(SSLSocketFactory factory, Proxy proxy, String proxyUsername, String proxyPassword, String host, int port)
- throws IOException {
- boolean success = false;
- Socket proxySocket = null;
- try {
- logger.debug("Attempting to use proxy : " + proxy.toString());
- InetSocketAddress proxyAddress = (InetSocketAddress) proxy.address();
- proxySocket = makeTunnel(host, port, proxyUsername, proxyPassword, proxyAddress);
-
- // Handshake with the origin server.
- if(proxySocket == null) {
- throw new ProtocolException("Unable to create tunnel through proxy server.");
- }
- Socket socket = factory.createSocket(proxySocket, host, port, true /* auto close */);
- success = true;
- return socket;
- } finally {
- if (!success) {
- Utilities.close(proxySocket);
- }
- }
- }
-
- @SuppressFBWarnings(value = "VA_FORMAT_STRING_USES_NEWLINE",
- justification = "use as according to RFC, not platform-linefeed")
- Socket makeTunnel(String host, int port, String proxyUsername,
- String proxyPassword, InetSocketAddress proxyAddress) throws IOException {
- if(host == null || port < 0 || host.isEmpty() || proxyAddress == null){
- throw new ProtocolException("Incorrect parameters to build tunnel.");
- }
- logger.debug("Creating socket for Proxy : " + proxyAddress.getAddress() + ":" + proxyAddress.getPort());
- Socket socket;
- try {
- ProxyClient client = new ProxyClient();
- client.getParams().setParameter("http.useragent", "java-apns");
- client.getHostConfiguration().setHost(host, port);
- String proxyHost = proxyAddress.getAddress().toString().substring(0, proxyAddress.getAddress().toString().indexOf("/"));
- client.getHostConfiguration().setProxy(proxyHost, proxyAddress.getPort());
-
-
- ProxyClient.ConnectResponse response = client.connect();
- socket = response.getSocket();
- if (socket == null) {
- ConnectMethod method = response.getConnectMethod();
- // Read the proxy's HTTP response.
- if(method.getStatusLine().getStatusCode() == 407) {
- // Proxy server returned 407. We will now try to connect with auth Header
- if(proxyUsername != null && proxyPassword != null) {
- socket = AuthenticateProxy(method, client,proxyHost, proxyAddress.getPort(),
- proxyUsername, proxyPassword);
- } else {
- throw new ProtocolException("Socket not created: " + method.getStatusLine());
- }
- }
- }
-
- } catch (Exception e) {
- throw new ProtocolException("Error occurred while creating proxy socket : " + e.toString());
- }
- if (socket != null) {
- logger.debug("Socket for proxy created successfully : " + socket.getRemoteSocketAddress().toString());
- }
- return socket;
- }
-
- private Socket AuthenticateProxy(ConnectMethod method, ProxyClient client,
- String proxyHost, int proxyPort,
- String proxyUsername, String proxyPassword) throws IOException {
- if("ntlm".equalsIgnoreCase(method.getProxyAuthState().getAuthScheme().getSchemeName())) {
- // If Auth scheme is NTLM, set NT credentials with blank host and domain name
- client.getState().setProxyCredentials(new AuthScope(proxyHost, proxyPort),
- new NTCredentials(proxyUsername, proxyPassword,"",""));
- } else {
- // If Auth scheme is Basic/Digest, set regular Credentials
- client.getState().setProxyCredentials(new AuthScope(proxyHost, proxyPort),
- new UsernamePasswordCredentials(proxyUsername, proxyPassword));
- }
-
- ProxyClient.ConnectResponse response = client.connect();
- Socket socket = response.getSocket();
-
- if (socket == null) {
- method = response.getConnectMethod();
- throw new ProtocolException("Proxy Authentication failed. Socket not created: "
- + method.getStatusLine());
- }
- return socket;
- }
-
-}
-
diff --git a/src/main/java/com/notnoop/apns/internal/Utilities.java b/src/main/java/com/notnoop/apns/internal/Utilities.java
deleted file mode 100644
index 1849098b..00000000
--- a/src/main/java/com/notnoop/apns/internal/Utilities.java
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.Socket;
-import java.security.GeneralSecurityException;
-import java.security.KeyStore;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.regex.Pattern;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManagerFactory;
-import com.notnoop.exceptions.InvalidSSLConfig;
-import com.notnoop.exceptions.NetworkIOException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public final class Utilities {
- private static Logger logger = LoggerFactory.getLogger(Utilities.class);
-
- public static final String SANDBOX_GATEWAY_HOST = "gateway.sandbox.push.apple.com";
- public static final int SANDBOX_GATEWAY_PORT = 2195;
-
- public static final String SANDBOX_FEEDBACK_HOST = "feedback.sandbox.push.apple.com";
- public static final int SANDBOX_FEEDBACK_PORT = 2196;
-
- public static final String PRODUCTION_GATEWAY_HOST = "gateway.push.apple.com";
- public static final int PRODUCTION_GATEWAY_PORT = 2195;
-
- public static final String PRODUCTION_FEEDBACK_HOST = "feedback.push.apple.com";
- public static final int PRODUCTION_FEEDBACK_PORT = 2196;
-
- public static final int MAX_PAYLOAD_LENGTH = 2048;
-
- private Utilities() { throw new AssertionError("Uninstantiable class"); }
-
- private static final Pattern pattern = Pattern.compile("[ -]");
- public static byte[] decodeHex(final String deviceToken) {
- final String hex = pattern.matcher(deviceToken).replaceAll("");
-
- final byte[] bts = new byte[hex.length() / 2];
- for (int i = 0; i < bts.length; i++) {
- bts[i] = (byte) (charVal(hex.charAt(2 * i)) * 16 + charVal(hex.charAt(2 * i + 1)));
- }
- return bts;
- }
-
- private static int charVal(final char a) {
- if ('0' <= a && a <= '9') {
- return (a - '0');
- } else if ('a' <= a && a <= 'f') {
- return (a - 'a') + 10;
- } else if ('A' <= a && a <= 'F') {
- return (a - 'A') + 10;
- } else {
- throw new RuntimeException("Invalid hex character: " + a);
- }
- }
-
- private static final char base[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
-
- public static String encodeHex(final byte[] bytes) {
- final char[] chars = new char[bytes.length * 2];
-
- for (int i = 0; i < bytes.length; ++i) {
- final int b = (bytes[i]) & 0xFF;
- chars[2 * i] = base[b >>> 4];
- chars[2 * i + 1] = base[b & 0xF];
- }
-
- return new String(chars);
- }
-
- public static byte[] toUTF8Bytes(final String s) {
- try {
- return s.getBytes("UTF-8");
- } catch (final UnsupportedEncodingException e) {
- throw new RuntimeException(e);
- }
- }
-
- public static byte[] marshall(final byte command, final byte[] deviceToken, final byte[] payload) {
- final ByteArrayOutputStream boas = new ByteArrayOutputStream();
- final DataOutputStream dos = new DataOutputStream(boas);
-
- try {
- dos.writeByte(command);
- dos.writeShort(deviceToken.length);
- dos.write(deviceToken);
- dos.writeShort(payload.length);
- dos.write(payload);
- return boas.toByteArray();
- } catch (final IOException e) {
- throw new AssertionError();
- }
- }
-
- public static byte[] marshallEnhanced(final byte command, final int identifier,
- final int expiryTime, final byte[] deviceToken, final byte[] payload) {
- final ByteArrayOutputStream boas = new ByteArrayOutputStream();
- final DataOutputStream dos = new DataOutputStream(boas);
-
- try {
- dos.writeByte(command);
- dos.writeInt(identifier);
- dos.writeInt(expiryTime);
- dos.writeShort(deviceToken.length);
- dos.write(deviceToken);
- dos.writeShort(payload.length);
- dos.write(payload);
- return boas.toByteArray();
- } catch (final IOException e) {
- throw new AssertionError();
- }
- }
-
- public static Map parseFeedbackStreamRaw(final InputStream in) {
- final Map result = new HashMap();
-
- final DataInputStream data = new DataInputStream(in);
-
- while (true) {
- try {
- final int time = data.readInt();
- final int dtLength = data.readUnsignedShort();
- final byte[] deviceToken = new byte[dtLength];
- data.readFully(deviceToken);
-
- result.put(deviceToken, time);
- } catch (final EOFException e) {
- break;
- } catch (final IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- return result;
- }
-
- public static Map parseFeedbackStream(final InputStream in) {
- final Map result = new HashMap();
-
- final Map raw = parseFeedbackStreamRaw(in);
- for (final Map.Entry entry : raw.entrySet()) {
- final byte[] dtArray = entry.getKey();
- final int time = entry.getValue(); // in seconds
-
- final Date date = new Date(time * 1000L); // in ms
- final String dtString = encodeHex(dtArray);
- result.put(dtString, date);
- }
-
- return result;
- }
-
- public static void close(final Closeable closeable) {
- logger.debug("close {}", closeable);
-
- try {
- if (closeable != null) {
- closeable.close();
- }
- } catch (final IOException e) {
- logger.debug("error while closing resource", e);
- }
- }
-
- public static void close(final Socket closeable) {
- logger.debug("close {}", closeable);
-
- try {
- if (closeable != null) {
- closeable.close();
- }
- } catch (final IOException e) {
- logger.debug("error while closing socket", e);
- }
- }
-
- public static void sleep(final int delay) {
- try {
- Thread.sleep(delay);
- } catch (final InterruptedException e1) {
- Thread.currentThread().interrupt();
- }
- }
-
- public static byte[] copyOf(final byte[] bytes) {
- final byte[] copy = new byte[bytes.length];
- System.arraycopy(bytes, 0, copy, 0, bytes.length);
- return copy;
- }
-
- public static byte[] copyOfRange(final byte[] original, final int from, final int to) {
- final int newLength = to - from;
- if (newLength < 0) {
- throw new IllegalArgumentException(from + " > " + to);
- }
- final byte[] copy = new byte[newLength];
- System.arraycopy(original, from, copy, 0,
- Math.min(original.length - from, newLength));
- return copy;
- }
-
- public static void wrapAndThrowAsRuntimeException(final Exception e) throws NetworkIOException {
- if (e instanceof IOException) {
- throw new NetworkIOException((IOException)e);
- } else if (e instanceof NetworkIOException) {
- throw (NetworkIOException)e;
- } else if (e instanceof RuntimeException) {
- throw (RuntimeException)e;
- } else {
- throw new RuntimeException(e);
- }
- }
-
- @SuppressWarnings({"PointlessArithmeticExpression", "PointlessBitwiseExpression"})
- public static int parseBytes(final int b1, final int b2, final int b3, final int b4) {
- return ((b1 << 3 * 8) & 0xFF000000)
- | ((b2 << 2 * 8) & 0x00FF0000)
- | ((b3 << 1 * 8) & 0x0000FF00)
- | ((b4 << 0 * 8) & 0x000000FF);
- }
-
- // @see http://stackoverflow.com/questions/119328/how-do-i-truncate-a-java-string-to-fit-in-a-given-number-of-bytes-once-utf-8-enc
- public static String truncateWhenUTF8(final String s, final int maxBytes) {
- int b = 0;
- for (int i = 0; i < s.length(); i++) {
- final char c = s.charAt(i);
-
- // ranges from http://en.wikipedia.org/wiki/UTF-8
- int skip = 0;
- int more;
- if (c <= 0x007f) {
- more = 1;
- }
- else if (c <= 0x07FF) {
- more = 2;
- } else if (c <= 0xd7ff) {
- more = 3;
- } else if (c <= 0xDFFF) {
- // surrogate area, consume next char as well
- more = 4;
- skip = 1;
- } else {
- more = 3;
- }
-
- if (b + more > maxBytes) {
- return s.substring(0, i);
- }
- b += more;
- i += skip;
- }
- return s;
- }
-
-}
diff --git a/src/main/java/com/notnoop/exceptions/ApnsDeliveryErrorException.java b/src/main/java/com/notnoop/exceptions/ApnsDeliveryErrorException.java
deleted file mode 100644
index c9b3bea9..00000000
--- a/src/main/java/com/notnoop/exceptions/ApnsDeliveryErrorException.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-package com.notnoop.exceptions;
-
-import com.notnoop.apns.DeliveryError;
-
-/**
- *
- * @author kkirch
- */
-public class ApnsDeliveryErrorException extends ApnsException {
-
- private final DeliveryError deliveryError;
-
- public ApnsDeliveryErrorException(DeliveryError error) {
- this.deliveryError = error;
- }
-
- @Override
- public String getMessage() {
- return "Failed to deliver notification with error code " + deliveryError.code();
- }
-
- public DeliveryError getDeliveryError() {
- return deliveryError;
- }
-
-
-}
diff --git a/src/main/java/com/notnoop/exceptions/ApnsException.java b/src/main/java/com/notnoop/exceptions/ApnsException.java
deleted file mode 100644
index f1725e5c..00000000
--- a/src/main/java/com/notnoop/exceptions/ApnsException.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.exceptions;
-
-/**
- * Base class for all the exceptions thrown in Apns Library
- */
-public abstract class ApnsException extends RuntimeException {
- private static final long serialVersionUID = -4756693306121825229L;
-
- public ApnsException() { super(); }
- public ApnsException(String message) { super(message); }
- public ApnsException(Throwable cause) { super(cause); }
- public ApnsException(String m, Throwable c) { super(m, c); }
-
-}
diff --git a/src/main/java/com/notnoop/exceptions/InvalidSSLConfig.java b/src/main/java/com/notnoop/exceptions/InvalidSSLConfig.java
deleted file mode 100644
index be975789..00000000
--- a/src/main/java/com/notnoop/exceptions/InvalidSSLConfig.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.exceptions;
-
-import java.io.IOException;
-import java.security.KeyManagementException;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
-
-/**
- * Signals that the the provided SSL context settings (e.g.
- * keystore path, password, encryption type, etc) are invalid
- *
- * This Exception can be caused by any of the following:
- *
- *
- * - {@link KeyStoreException}
- * - {@link NoSuchAlgorithmException}
- * - {@link CertificateException}
- * - {@link IOException}
- * - {@link UnrecoverableKeyException}
- * - {@link KeyManagementException}
- *
- *
- */
-public class InvalidSSLConfig extends ApnsException {
- private static final long serialVersionUID = -7283168775864517167L;
-
- public InvalidSSLConfig() { super(); }
- public InvalidSSLConfig(String message) { super(message); }
- public InvalidSSLConfig(Throwable cause) { super(cause); }
- public InvalidSSLConfig(String m, Throwable c) { super(m, c); }
-
-}
diff --git a/src/main/java/com/notnoop/exceptions/NetworkIOException.java b/src/main/java/com/notnoop/exceptions/NetworkIOException.java
deleted file mode 100644
index df84eb5e..00000000
--- a/src/main/java/com/notnoop/exceptions/NetworkIOException.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.exceptions;
-
-import java.io.IOException;
-
-/**
- * Thrown to indicate that that a network operation has failed:
- * (e.g. connectivity problems, domain cannot be found, network
- * dropped).
- */
-public class NetworkIOException extends ApnsException {
- private static final long serialVersionUID = 3353516625486306533L;
-
- private boolean resend;
-
- public NetworkIOException() { super(); }
- public NetworkIOException(String message) { super(message); }
- public NetworkIOException(IOException cause) { super(cause); }
- public NetworkIOException(String m, IOException c) { super(m, c); }
- public NetworkIOException(IOException cause, boolean resend) {
- super(cause);
- this.resend = resend;
- }
-
- /**
- * Identifies whether an exception was thrown during a resend of a
- * message or not. In this case a resend refers to whether the
- * message is being resent from the buffer of messages internal.
- * This would occur if we sent 5 messages quickly to APNS:
- * 1,2,3,4,5 and the 3 message was rejected. We would
- * then need to resend 4 and 5. If a network exception was
- * triggered when doing this, then the resend flag will be
- * {@code true}.
- * @return {@code true} for an exception trigger during a resend, otherwise {@code false}.
- */
- public boolean isResend() {
- return resend;
- }
-
-}
diff --git a/src/main/java/com/notnoop/exceptions/RuntimeIOException.java b/src/main/java/com/notnoop/exceptions/RuntimeIOException.java
deleted file mode 100644
index 1a447bd5..00000000
--- a/src/main/java/com/notnoop/exceptions/RuntimeIOException.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.exceptions;
-
-import java.io.IOException;
-
-/**
- * Signals that an I/O exception of some sort has occurred. This
- * class is the general class of exceptions produced by failed or
- * interrupted I/O operations.
- *
- * This is a RuntimeException, unlike the java.io.IOException
- */
-public class RuntimeIOException extends ApnsException {
- private static final long serialVersionUID = 8665285084049041306L;
-
- public RuntimeIOException() { super(); }
- public RuntimeIOException(String message) { super(message); }
- public RuntimeIOException(IOException cause) { super(cause); }
- public RuntimeIOException(String m, IOException c) { super(m, c); }
-
-}
diff --git a/src/test/java/com/notnoop/apns/APNSTest.java b/src/test/java/com/notnoop/apns/APNSTest.java
deleted file mode 100644
index aefe16f2..00000000
--- a/src/test/java/com/notnoop/apns/APNSTest.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns;
-
-import org.junit.Test;
-import static org.junit.Assert.*;
-import static org.hamcrest.CoreMatchers.*;
-
-/**
- * Silly Tests
- */
-public class APNSTest {
-
- @Test
- public void testInstances() {
- assertThat(APNS.newPayload(), isA(PayloadBuilder.class));
- assertThat(APNS.newService(), isA(ApnsServiceBuilder.class));
- }
-
- @Test
- public void payloadShouldGetNewInstances() {
- assertNotSame(APNS.newPayload(), APNS.newPayload());
- }
-
- @Test
- public void newServiceGetNewInstances() {
- assertNotSame(APNS.newService(), APNS.newService());
- }
-}
diff --git a/src/test/java/com/notnoop/apns/AbstractApnsServerSocket.java b/src/test/java/com/notnoop/apns/AbstractApnsServerSocket.java
deleted file mode 100644
index 7a1efdcd..00000000
--- a/src/test/java/com/notnoop/apns/AbstractApnsServerSocket.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns;
-
-import java.io.IOException;
-import java.net.Socket;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.TimeUnit;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLServerSocket;
-import javax.net.ssl.SSLServerSocketFactory;
-
-/**
- * Represents the Apple server. This allows testing outside of the Apple
- * servers. Sub-classes should implement the specific handing of new socket
- * connections.
- */
-public abstract class AbstractApnsServerSocket {
- private final SSLServerSocket serverSocket;
- private final ExecutorService executorService;
- private final ApnsServerExceptionDelegate exceptionDelegate;
-
- public AbstractApnsServerSocket(SSLContext sslContext, int port,
- ExecutorService executorService,
- ApnsServerExceptionDelegate exceptionDelegate) throws IOException {
- SSLServerSocketFactory serverSocketFactory = sslContext
- .getServerSocketFactory();
- serverSocket = (SSLServerSocket) serverSocketFactory
- .createServerSocket(port);
- this.executorService = executorService;
- this.exceptionDelegate = exceptionDelegate;
- }
-
- /**
- * Start the server accept process. This method is non-blocking.
- */
- public final void start() {
- new Thread(new Runnable() {
- @Override
- public void run() {
- startAccept();
- }
- }).start();
- }
-
- @SuppressWarnings("InfiniteLoopStatement")
- private void startAccept() {
-
- try {
- while (true) {
- Socket accept = serverSocket.accept();
- // Work around JVM deadlock ... https://community.oracle.com/message/10989561#10989561
- accept.setSoLinger(true, 1);
- executorService.execute(new SocketHandler(accept));
- }
- } catch (IOException ioe) {
- executorService.shutdown();
- }
- }
-
- /**
- * Stops the server socket. This method is blocking.
- */
- public final void stop() {
- try {
- serverSocket.close();
- } catch (IOException ioe) {
- // don't care
- }
-
- executorService.shutdown(); // Disable new tasks from being submitted
- try {
- // Wait a while for existing tasks to terminate
- if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
- executorService.shutdownNow(); // Cancel currently executing
- // tasks
- // Wait a while for tasks to respond to being cancelled
- if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
- System.err.println("Pool did not terminate");
- }
- }
- } catch (InterruptedException ie) {
- // (Re-)Cancel if current thread also interrupted
- executorService.shutdownNow();
- // Preserve interrupt status
- Thread.currentThread().interrupt();
- }
- }
-
- private class SocketHandler implements Runnable {
- private final Socket socket;
-
- SocketHandler(Socket socket) {
- this.socket = socket;
- }
-
- @Override
- public void run() {
- try {
- handleSocket(socket);
- } catch (IOException ioe) {
- exceptionDelegate.handleRequestFailed(ioe);
- }
- }
- }
-
- abstract void handleSocket(Socket socket) throws IOException;
-}
diff --git a/src/test/java/com/notnoop/apns/ApnsFeedbackServerSocket.java b/src/test/java/com/notnoop/apns/ApnsFeedbackServerSocket.java
deleted file mode 100644
index 254a108d..00000000
--- a/src/test/java/com/notnoop/apns/ApnsFeedbackServerSocket.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns;
-
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.net.Socket;
-import java.util.Date;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.concurrent.ExecutorService;
-
-import javax.net.ssl.SSLContext;
-
-/**
- * Represents the Apple Feedback server. This allows testing outside of the
- * Apple servers.
- */
-public class ApnsFeedbackServerSocket extends AbstractApnsServerSocket {
- private final ApnsServerService requestDelegate;
-
- public ApnsFeedbackServerSocket(SSLContext sslContext, int port,
- ExecutorService executorService, ApnsServerService requestDelegate,
- ApnsServerExceptionDelegate exceptionDelegate) throws IOException {
- super(sslContext, port, executorService, exceptionDelegate);
- this.requestDelegate = requestDelegate;
- }
-
- @Override
- void handleSocket(Socket socket) throws IOException {
- Map inactiveDevices = requestDelegate
- .getInactiveDevices();
- DataOutputStream dataStream = new DataOutputStream(
- socket.getOutputStream());
- for (Entry entry : inactiveDevices.entrySet()) {
- int time = (int) (entry.getValue().getTime() / 1000L);
- dataStream.writeInt(time);
- byte[] bytes = entry.getKey();
- dataStream.writeShort(bytes.length);
- dataStream.write(bytes);
- }
- dataStream.close();
- }
-}
\ No newline at end of file
diff --git a/src/test/java/com/notnoop/apns/ApnsGatewayServerSocket.java b/src/test/java/com/notnoop/apns/ApnsGatewayServerSocket.java
deleted file mode 100644
index 3e04d5b0..00000000
--- a/src/test/java/com/notnoop/apns/ApnsGatewayServerSocket.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns;
-
-import java.io.BufferedOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.Socket;
-import java.util.concurrent.ExecutorService;
-import javax.net.ssl.SSLContext;
-
-/**
- * Represents the Apple APNS server. This allows testing outside of the Apple
- * servers.
- */
-@SuppressWarnings("deprecation")
-public class ApnsGatewayServerSocket extends AbstractApnsServerSocket {
- private final ApnsServerService apnsServerService;
-
- public ApnsGatewayServerSocket(SSLContext sslContext, int port,
- ExecutorService executorService,
- ApnsServerService apnsServerService,
- ApnsServerExceptionDelegate exceptionDelegate) throws IOException {
- super(sslContext, port, executorService, exceptionDelegate);
- this.apnsServerService = apnsServerService;
- }
-
- @Override
- void handleSocket(Socket socket) throws IOException {
- InputStream inputStream = socket.getInputStream();
- DataInputStream dataInputStream = new DataInputStream(inputStream);
- while (true) {
- int identifier = 0;
- try {
- int read = dataInputStream.read();
- if (read == -1) {
- break;
- }
-
- boolean enhancedFormat = read == 1;
- int expiry = 0;
- if (enhancedFormat) {
- identifier = dataInputStream.readInt();
- expiry = dataInputStream.readInt();
- }
-
- int deviceTokenLength = dataInputStream.readShort();
- byte[] deviceTokenBytes = toArray(inputStream,
- deviceTokenLength);
-
- int payloadLength = dataInputStream.readShort();
- byte[] payloadBytes = toArray(inputStream, payloadLength);
-
- ApnsNotification message;
- if (enhancedFormat) {
- message = new EnhancedApnsNotification(identifier, expiry,
- deviceTokenBytes, payloadBytes);
- } else {
- message = new SimpleApnsNotification(deviceTokenBytes,
- payloadBytes);
- }
- apnsServerService.messageReceived(message);
- } catch (IOException ioe) {
- writeResponse(socket, identifier, 8, 1);
- break;
- } catch (Exception e) {
- writeResponse(socket, identifier, 8, 1);
- break;
- }
- }
- }
-
- private void writeResponse(Socket socket, int identifier, int command,
- int status) {
- try {
- BufferedOutputStream bos = new BufferedOutputStream(
- socket.getOutputStream());
- DataOutputStream dataOutputStream = new DataOutputStream(bos);
- dataOutputStream.writeByte(command);
- dataOutputStream.writeByte(status);
- dataOutputStream.writeInt(identifier);
- dataOutputStream.flush();
- } catch (IOException ioe) {
- // if we can't write a response, nothing we can do
- }
- }
-
- private byte[] toArray(InputStream inputStream, int size)
- throws IOException {
- byte[] bytes = new byte[size];
- final DataInputStream dis = new DataInputStream(inputStream);
- dis.readFully(bytes);
- return bytes;
- }
-}
\ No newline at end of file
diff --git a/src/test/java/com/notnoop/apns/ApnsServerExceptionDelegate.java b/src/test/java/com/notnoop/apns/ApnsServerExceptionDelegate.java
deleted file mode 100644
index 431f0d63..00000000
--- a/src/test/java/com/notnoop/apns/ApnsServerExceptionDelegate.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns;
-
-/**
- * A delegate that gets notified of failures.
- */
-public interface ApnsServerExceptionDelegate {
-
- void handleRequestFailed(Throwable thr);
-
- public static final ApnsServerExceptionDelegate EMPTY = new ApnsServerExceptionDelegate() {
- @Override
- public void handleRequestFailed(Throwable thr) {
- }
- };
-}
\ No newline at end of file
diff --git a/src/test/java/com/notnoop/apns/ApnsServerService.java b/src/test/java/com/notnoop/apns/ApnsServerService.java
deleted file mode 100644
index d7de5a24..00000000
--- a/src/test/java/com/notnoop/apns/ApnsServerService.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns;
-
-import java.util.Collections;
-import java.util.Date;
-import java.util.Map;
-
-/**
- * A delegate that gets notified of the delivery of messages.
- */
-public interface ApnsServerService {
-
-
- /**
- * Called when message was successfully received
- *
- * @param message the notification that was received.
- * @throws Exception
- */
- void messageReceived(ApnsNotification message) throws Exception;
-
-
- /**
- * Called to determine if any of the devices is judged to be inactive.
- *
- * @return a map of inactive devices.
- */
- Map getInactiveDevices();
-
- public static final ApnsServerService EMPTY = new ApnsServerService() {
- @Override
- public void messageReceived(ApnsNotification message) throws Exception {
- }
-
- @Override
- public Map getInactiveDevices() {
- return Collections.emptyMap();
- }
- };
-}
\ No newline at end of file
diff --git a/src/test/java/com/notnoop/apns/ApnsServerSocketBuilder.java b/src/test/java/com/notnoop/apns/ApnsServerSocketBuilder.java
deleted file mode 100644
index fc78aad2..00000000
--- a/src/test/java/com/notnoop/apns/ApnsServerSocketBuilder.java
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns;
-
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.KeyStore;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.SynchronousQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import javax.net.ssl.SSLContext;
-
-import com.notnoop.apns.internal.SSLContextBuilder;
-import com.notnoop.apns.internal.Utilities;
-import com.notnoop.exceptions.InvalidSSLConfig;
-import com.notnoop.exceptions.RuntimeIOException;
-import static com.notnoop.apns.internal.Utilities.*;
-
-/**
- * The class is used to create instances of {@link ApnsService}.
- *
- * Note that this class is not synchronized. If multiple threads access a
- * {@code ApnsServiceBuilder} instance concurrently, and at least on of the
- * threads modifies one of the attributes structurally, it must be synchronized
- * externally.
- *
- * Starting a new {@code ApnsService} is easy:
- *
- *
- * ApnsService = APNS.newService()
- * .withCert("/path/to/certificate.p12", "MyCertPassword")
- * .withSandboxDestination().build()
- *
- */
-public class ApnsServerSocketBuilder {
- private static final String KEYSTORE_TYPE = "PKCS12";
- private static final String KEY_ALGORITHM = "sunx509";
-
- private SSLContext sslContext;
- private int gatewayPort = -1;
- private int feedbackPort = -1;
- private ExecutorService executor;
- private ApnsServerService serverService = ApnsServerService.EMPTY;
- private ApnsServerExceptionDelegate exceptionDelegate = ApnsServerExceptionDelegate.EMPTY;
-
- /**
- * Constructs a new instance of {@code ApnsServiceBuilder}
- */
- public ApnsServerSocketBuilder() {
- sslContext = null;
- }
-
- /**
- * Specify the certificate used to connect to Apple APNS servers. This
- * relies on the path (absolute or relative to working path) to the keystore
- * (*.p12) containing the certificate, along with the given password.
- *
- * The keystore needs to be of PKCS12 and the keystore needs to be encrypted
- * using the SunX509 algorithm. Both of these settings are the default.
- *
- * This library does not support password-less p12 certificates, due to a
- * Oracle Java library Bug
- * 6415637. There are three workarounds: use a password-protected
- * certificate, use a different boot Java SDK implementation, or construct
- * the `SSLContext` yourself! Needless to say, the password-protected
- * certificate is most recommended option.
- *
- * @param fileName
- * the path to the certificate
- * @param password
- * the password of the keystore
- * @return this
- * @throws RuntimeIOException
- * if it {@code fileName} cannot be found or read
- * @throws InvalidSSLConfig
- * if fileName is invalid Keystore or the password is invalid
- */
- public ApnsServerSocketBuilder withCert(String fileName, String password)
- throws RuntimeIOException, InvalidSSLConfig {
- FileInputStream stream = null;
- try {
- stream = new FileInputStream(fileName);
- return withCert(stream, password);
- } catch (FileNotFoundException e) {
- throw new RuntimeIOException(e);
- } finally {
- Utilities.close(stream);
- }
- }
-
- /**
- * Specify the certificate used to connect to Apple APNS servers. This
- * relies on the stream of keystore (*.p12) containing the certificate,
- * along with the given password.
- *
- * The keystore needs to be of PKCS12 and the keystore needs to be encrypted
- * using the SunX509 algorithm. Both of these settings are the default.
- *
- * This library does not support password-less p12 certificates, due to a
- * Oracle Java library Bug
- * 6415637. There are three workarounds: use a password-protected
- * certificate, use a different boot Java SDK implementation, or construct
- * the `SSLContext` yourself! Needless to say, the password-protected
- * certificate is most recommended option.
- *
- * @param stream
- * the keystore represented as input stream
- * @param password
- * the password of the keystore
- * @return this
- * @throws InvalidSSLConfig
- * if stream is invalid Keystore or the password is invalid
- */
- public ApnsServerSocketBuilder withCert(InputStream stream, String password)
- throws InvalidSSLConfig {
- assertPasswordNotEmpty(password);
- return withSSLContext(new SSLContextBuilder()
- .withAlgorithm(KEY_ALGORITHM)
- .withCertificateKeyStore(stream, password, KEYSTORE_TYPE)
- .withDefaultTrustKeyStore()
- .build());
- }
-
- /**
- * Specify the certificate used to connect to Apple APNS servers. This
- * relies on a keystore (*.p12) containing the certificate, along with the
- * given password.
- *
- * This library does not support password-less p12 certificates, due to a
- * Oracle Java library Bug
- * 6415637. There are three workarounds: use a password-protected
- * certificate, use a different boot Java SDK implementation, or construct
- * the `SSLContext` yourself! Needless to say, the password-protected
- * certificate is most recommended option.
- *
- * @param keyStore the keystore
- * @param password the password of the keystore
- * @return this
- * @throws InvalidSSLConfig if stream is invalid Keystore or the password is invalid
- */
- public ApnsServerSocketBuilder withCert(KeyStore keyStore, String password)
- throws InvalidSSLConfig {
- assertPasswordNotEmpty(password);
- return withSSLContext(new SSLContextBuilder()
- .withAlgorithm(KEY_ALGORITHM)
- .withCertificateKeyStore(keyStore, password)
- .withDefaultTrustKeyStore()
- .build());
- }
-
- private void assertPasswordNotEmpty(String password) {
- if (password == null || password.length() == 0) {
- throw new IllegalArgumentException(
- "Passwords must be specified."
- + "Oracle Java SDK does not support passwordless p12 certificates");
- }
- }
-
- /**
- * Specify the SSLContext that should be used to initiate the connection to
- * Apple Server.
- *
- * Most clients would use {@link #withCert(InputStream, String)} or
- * {@link #withCert(String, String)} instead. But some clients may need to
- * represent the Keystore in a different format than supported.
- *
- * @param sslContext
- * Context to be used to create secure connections
- * @return this
- */
- public ApnsServerSocketBuilder withSSLContext(SSLContext sslContext) {
- this.sslContext = sslContext;
- return this;
- }
-
- /**
- * Specify the gateway server for sending Apple iPhone notifications.
- *
- * @param port
- * port of the notification gateway of Apple
- * @return this
- */
- public ApnsServerSocketBuilder withGatewayDestination(int port) {
- this.gatewayPort = port;
- return this;
- }
-
- /**
- * Specify the Feedback for getting failed devices from Apple iPhone Push
- * servers.
- *
- * @param port
- * port of the feedback server of Apple
- * @return this
- */
- public ApnsServerSocketBuilder withFeedbackDestination(int port) {
- this.feedbackPort = port;
- return this;
- }
-
- /**
- * Specify to use the Apple sandbox servers as iPhone gateway and feedback
- * servers.
- *
- * This is desired when in testing and pushing notifications with a
- * development provision.
- *
- * @return this
- */
- public ApnsServerSocketBuilder withSandboxDestination() {
- return withGatewayDestination(SANDBOX_GATEWAY_PORT)
- .withFeedbackDestination(SANDBOX_FEEDBACK_PORT);
- }
-
- /**
- * Specify to use the Apple Production servers as iPhone gateway and
- * feedback servers.
- *
- * This is desired when sending notifications to devices with a production
- * provision (whether through App Store or Ad hoc distribution).
- *
- * @return this
- */
- public ApnsServerSocketBuilder withProductionDestination() {
- return withGatewayDestination(PRODUCTION_GATEWAY_PORT)
- .withFeedbackDestination(PRODUCTION_FEEDBACK_PORT);
- }
-
- /**
- * Constructs a pool of connections to the notification servers.
- *
- * Apple servers recommend using a pooled connection up to 15 concurrent
- * persistent connections to the gateways.
- *
- * Note: This option has no effect when using non-blocking connections.
- */
- public ApnsServerSocketBuilder asPool(int maxConnections) {
- return asPool(new ThreadPoolExecutor(maxConnections, Integer.MAX_VALUE,
- 60L, TimeUnit.SECONDS, new SynchronousQueue()));
- }
-
- /**
- * Constructs a pool of connections to the notification servers.
- *
- * Apple servers recommend using a pooled connection up to 15 concurrent
- * persistent connections to the gateways.
- *
- * Note: This option has no effect when using non-blocking connections.
- */
- public ApnsServerSocketBuilder asPool(ExecutorService executor) {
- this.executor = executor;
- return this;
- }
-
- /**
- * Sets the delegate of the service, that gets notified of the status of
- * message delivery.
- *
- * Note: This option has no effect when using non-blocking connections.
- */
- public ApnsServerSocketBuilder withService(ApnsServerService serverService) {
- this.serverService = serverService == null ? ApnsServerService.EMPTY
- : serverService;
- return this;
- }
-
- /**
- * Sets the delegate of the service, that gets notified of the status of
- * message delivery.
- *
- * Note: This option has no effect when using non-blocking connections.
- */
- public ApnsServerSocketBuilder withDelegate(
- ApnsServerExceptionDelegate exceptionDelegate) {
- this.exceptionDelegate = exceptionDelegate == null ? ApnsServerExceptionDelegate.EMPTY
- : exceptionDelegate;
- return this;
- }
-
- /**
- * Returns a fully initialized instance of {@link ApnsService}, according to
- * the requested settings.
- *
- * @return a new instance of ApnsService
- * @throws IOException
- */
- public ApnsSocketService build() throws IOException {
- checkInitialization();
-
- AbstractApnsServerSocket apnsPushServerSocket = new ApnsGatewayServerSocket(
- sslContext, gatewayPort, executor, serverService,
- exceptionDelegate);
- AbstractApnsServerSocket apnsFeedbackServerSocket = new ApnsFeedbackServerSocket(
- sslContext, feedbackPort, executor, serverService,
- exceptionDelegate);
-
- ApnsSocketService service = new ApnsSocketService(apnsPushServerSocket,
- apnsFeedbackServerSocket);
- service.start();
- return service;
- }
-
- private void checkInitialization() {
- if (sslContext == null) {
- throw new IllegalStateException(
- "SSL Certificates and attribute are not initialized\n"
- + "Use .withCert() methods.");
- }
-
- if (executor == null) {
- throw new IllegalStateException(
- "SSL Certificates and attribute are not initialized\n"
- + "Use .withCert() methods.");
- }
-
- if (gatewayPort == -1 || feedbackPort == -1) {
- throw new IllegalStateException(
- "The Destination APNS server is not stated\n"
- + "Use .withDestination(), withSandboxDestination(), "
- + "or withProductionDestination().");
- }
- }
-}
diff --git a/src/test/java/com/notnoop/apns/ApnsSocketService.java b/src/test/java/com/notnoop/apns/ApnsSocketService.java
deleted file mode 100644
index 25378490..00000000
--- a/src/test/java/com/notnoop/apns/ApnsSocketService.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns;
-
-import java.io.IOException;
-
-public class ApnsSocketService {
- private final AbstractApnsServerSocket apnsPushServerSocket;
- private final AbstractApnsServerSocket apnsFeedbackServerSocket;
-
- public ApnsSocketService(AbstractApnsServerSocket apnsPushServerSocket,
- AbstractApnsServerSocket apnsFeedbackServerSocket)
- throws IOException {
- this.apnsPushServerSocket = apnsPushServerSocket;
- this.apnsFeedbackServerSocket = apnsFeedbackServerSocket;
- }
-
- public void start() {
- apnsPushServerSocket.start();
- apnsFeedbackServerSocket.start();
- }
-
- public void stop() {
- apnsPushServerSocket.stop();
- apnsFeedbackServerSocket.stop();
- }
-}
\ No newline at end of file
diff --git a/src/test/java/com/notnoop/apns/MainClass.java b/src/test/java/com/notnoop/apns/MainClass.java
deleted file mode 100644
index e737ce4d..00000000
--- a/src/test/java/com/notnoop/apns/MainClass.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns;
-
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.util.Date;
-import java.util.Map;
-import java.util.Map.Entry;
-import com.notnoop.exceptions.InvalidSSLConfig;
-
-public class MainClass {
-
- /**
- * @param args Program arguments
- * @throws FileNotFoundException
- * @throws InvalidSSLConfig
- */
- public static void main(final String[] args) throws InvalidSSLConfig, FileNotFoundException {
- if (args.length != 4) {
- System.err.println("Usage: test \ntest p ./cert abc123 token");
- System.exit(777);
- }
-
- final ApnsDelegate delegate = new ApnsDelegate() {
- public void messageSent(final ApnsNotification message, final boolean resent) {
- System.out.println("Sent message " + message + " Resent: " + resent);
- }
-
- public void messageSendFailed(final ApnsNotification message, final Throwable e) {
- System.out.println("Failed message " + message);
-
- }
-
- public void connectionClosed(final DeliveryError e, final int messageIdentifier) {
- System.out.println("Closed connection: " + messageIdentifier + "\n deliveryError " + e.toString());
- }
-
- public void cacheLengthExceeded(final int newCacheLength) {
- System.out.println("cacheLengthExceeded " + newCacheLength);
-
- }
-
- public void notificationsResent(final int resendCount) {
- System.out.println("notificationResent " + resendCount);
- }
- };
-
- final ApnsService svc = APNS.newService()
- .withAppleDestination("p".equals(args[0]))
- .withCert(new FileInputStream(args[1]), args[2])
- .withDelegate(delegate)
- .build();
-
- final String goodToken = args[3];
-
- final String payload = APNS.newPayload().alertBody("Wrzlmbrmpf dummy alert").build();
-
- svc.start();
- System.out.println("Sending message");
- final ApnsNotification goodMsg = svc.push(goodToken, payload);
- System.out.println("Message id: " + goodMsg.getIdentifier());
-
- System.out.println("Getting inactive devices");
-
- final Map inactiveDevices = svc.getInactiveDevices();
-
- for (final Entry ent : inactiveDevices.entrySet()) {
- System.out.println("Inactive " + ent.getKey() + " at date " + ent.getValue());
- }
- System.out.println("Stopping service");
- svc.stop();
- }
-}
diff --git a/src/test/java/com/notnoop/apns/PayloadBuilderTest.java b/src/test/java/com/notnoop/apns/PayloadBuilderTest.java
deleted file mode 100644
index 95ebe28b..00000000
--- a/src/test/java/com/notnoop/apns/PayloadBuilderTest.java
+++ /dev/null
@@ -1,573 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns;
-
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Random;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.notnoop.apns.internal.Utilities;
-import org.junit.Test;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.core.IsNot.*;
-import static org.hamcrest.core.StringContains.*;
-import static org.junit.Assert.*;
-
-@SuppressWarnings("deprecation")
-public class PayloadBuilderTest {
-
- @Test
- public void testEmpty() {
- final PayloadBuilder builder = new PayloadBuilder();
-
- final String expected = "{\"aps\":{}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
- }
-
- @Test
- public void testOneAps() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.alertBody("test");
-
- final String expected = "{\"aps\":{\"alert\":\"test\"}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
- }
-
- @Test
- public void testTwoAps() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.alertBody("test");
- builder.badge(9);
-
- final String expected = "{\"aps\":{\"alert\":\"test\",\"badge\":9}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
- }
-
- @Test
- public void testSafariAps() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.alertBody("test");
- builder.alertTitle("Test Title");
- builder.actionKey("View");
- builder.urlArgs("arg1", "arg2", "arg3");
-
- final String expected = "{\"aps\":{\"alert\":{\"body\":\"test\",\"title\":\"Test Title\",\"action-loc-key\":\"View\"},\"url-args\":[\"arg1\",\"arg2\",\"arg3\"]}}";
- assertEqualsJson(expected, builder.build());
- }
-
- @Test
- public void testTwoApsMultipleBuilds() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.alertBody("test");
- builder.badge(9);
-
- final String expected = "{\"aps\":{\"alert\":\"test\",\"badge\":9}}";
- assertEqualsJson(expected, builder.build());
- assertEqualsJson(expected, builder.build());
- }
-
- @Test
- public void testIncludeBadge() {
- final String badge0 = APNS.newPayload().badge(0).toString();
- final String badgeNo = APNS.newPayload().clearBadge().toString();
-
- final String expected = "{\"aps\":{\"badge\":0}}";
- assertEqualsJson(expected, badge0);
- assertEqualsJson(expected, badgeNo);
- }
-
- @Test
- public void localizedTitleKeyAndArguments() {
- final PayloadBuilder builder = new PayloadBuilder()
- .localizedTitleKey("GAME_PLAY_REQUEST_FORMAT")
- .localizedTitleArguments("Jenna", "Frank");
- builder.sound("chime");
-
- final String expected = "{\"aps\":{\"sound\":\"chime\",\"alert\":{\"title-loc-key\":\"GAME_PLAY_REQUEST_FORMAT\",\"title-loc-args\":[\"Jenna\",\"Frank\"]}}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
- }
-
- @Test
- public void localizedOneWithArray() {
- final PayloadBuilder builder = new PayloadBuilder()
- .localizedKey("GAME_PLAY_REQUEST_FORMAT")
- .localizedArguments("Jenna", "Frank");
- builder.sound("chime");
-
- final String expected = "{\"aps\":{\"sound\":\"chime\",\"alert\":{\"loc-key\":\"GAME_PLAY_REQUEST_FORMAT\",\"loc-args\":[\"Jenna\",\"Frank\"]}}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
- }
-
- @Test
- public void localizedOneWithVarargs() {
- final PayloadBuilder builder = new PayloadBuilder()
- .localizedKey("GAME_PLAY_REQUEST_FORMAT")
- .localizedArguments("Jenna", "Frank");
- builder.sound("chime");
-
- final String expected = "{\"aps\":{\"sound\":\"chime\",\"alert\":{\"loc-key\":\"GAME_PLAY_REQUEST_FORMAT\",\"loc-args\":[\"Jenna\",\"Frank\"]}}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
- }
-
- @Test
- public void localizedTwo() {
- final PayloadBuilder builder =
- new PayloadBuilder()
- .sound("chime")
- .localizedKey("GAME_PLAY_REQUEST_FORMAT")
- .localizedArguments("Jenna", "Frank");
-
- final String expected = "{\"aps\":{\"sound\":\"chime\",\"alert\":{\"loc-key\":\"GAME_PLAY_REQUEST_FORMAT\",\"loc-args\":[\"Jenna\",\"Frank\"]}}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
- }
-
- @Test
- public void customFieldSimple() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.alertBody("test");
-
- builder.customField("ache1", "what");
- builder.customField("ache2", 2);
-
- final String expected = "{\"ache1\":\"what\",\"ache2\":2,\"aps\":{\"alert\":\"test\"}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
- }
-
- @Test
- public void customFieldArray() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.alertBody("test");
-
- builder.customField("ache1", Arrays.asList("a1", "a2"));
- builder.customField("ache2", new int[] { 1, 2 } );
-
- final String expected = "{\"ache1\":[\"a1\",\"a2\"],\"ache2\":[1,2],\"aps\":{\"alert\":\"test\"}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
- }
-
- @Test
- public void customBody() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.alertBody("what").actionKey("Cancel");
-
- final String expected = "{\"aps\":{\"alert\":{\"action-loc-key\":\"Cancel\",\"body\":\"what\"}}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
- }
-
- @Test
- public void multipleBuildCallsWithCustomBody() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.alertBody("what").actionKey("Cancel");
-
- final String expected = "{\"aps\":{\"alert\":{\"action-loc-key\":\"Cancel\",\"body\":\"what\"}}}";
- assertEqualsJson(expected, builder.build());
- assertEqualsJson(expected, builder.build());
- }
-
- @Test
- public void customBodyReverseOrder() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.actionKey("Cancel").alertBody("what");
-
- final String expected = "{\"aps\":{\"alert\":{\"action-loc-key\":\"Cancel\",\"body\":\"what\"}}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
- }
-
- @Test
- public void alertNoView() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.actionKey(null).alertBody("what");
-
- final String expected = "{\"aps\":{\"alert\":{\"action-loc-key\":null,\"body\":\"what\"}}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
- }
-
- @Test
- public void alertNoViewSimpler() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.noActionButton().alertBody("what");
-
- final String expected = "{\"aps\":{\"alert\":{\"action-loc-key\":null,\"body\":\"what\"}}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
- }
-
- @Test
- public void alertWithImageOnly() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.launchImage("/test");
-
- final String expected = "{\"aps\":{\"alert\":{\"launch-image\":\"/test\"}}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
- }
-
- @Test
- public void alertWithImageAndText() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.launchImage("/test").alertBody("hello");
-
- final String expected = "{\"aps\":{\"alert\":{\"launch-image\":\"/test\",\"body\":\"hello\"}}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
- }
-
- @Test
- public void emptyApsWithFields() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.customField("achme2", new int[] { 5, 8 } );
-
- final String expected = "{\"achme2\":[5,8],\"aps\":{}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
- }
-
- @Test
- public void abitComplicated() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.customField("achme", "foo");
- builder.sound("chime");
- builder.localizedKey("GAME_PLAY_REQUEST_FORMAT")
- .localizedArguments("Jenna", "Frank");
-
- final String expected = "{\"achme\":\"foo\",\"aps\":{\"sound\":\"chime\",\"alert\":{\"loc-key\":\"GAME_PLAY_REQUEST_FORMAT\",\"loc-args\":[\"Jenna\",\"Frank\"]}}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
- }
-
- @Test
- public void multipleBuildAbitComplicated() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.customField("achme", "foo");
- builder.sound("chime");
- builder.localizedKey("GAME_PLAY_REQUEST_FORMAT")
- .localizedArguments("Jenna", "Frank");
-
- final String expected = "{\"achme\":\"foo\",\"aps\":{\"sound\":\"chime\",\"alert\":{\"loc-key\":\"GAME_PLAY_REQUEST_FORMAT\",\"loc-args\":[\"Jenna\",\"Frank\"]}}}";
- assertEqualsJson(expected, builder.build());
- assertEqualsJson(expected, builder.build());
- }
-
- @Test
- public void copyReturnsNewInstance() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.sound("chime");
- final PayloadBuilder copy = builder.copy();
- copy.badge(5);
-
- assertNotSame(builder, copy);
-
- final String expected = "{\"aps\":{\"sound\":\"chime\"}}";
- assertEqualsJson(expected, builder.build());
-
- final String copyExpected = "{\"aps\":{\"sound\":\"chime\",\"badge\":5}}";
- assertEqualsJson(copyExpected, copy.build());
- }
-
- @Test
- public void simpleEnglishLength() {
- final PayloadBuilder builder = new PayloadBuilder().alertBody("test");
- final String expected = "{\"aps\":{\"alert\":\"test\"}}";
- assertEqualsJson(expected, builder.build());
- final int actualLength = Utilities.toUTF8Bytes(expected).length;
- assertEquals(actualLength, builder.length());
- assertFalse(builder.isTooLong());
- }
-
- @Test
- public void abitComplicatedEnglishLength() {
- final byte[] dtBytes = new byte[32];
- new Random().nextBytes(dtBytes);
-
- final String deviceToken = Utilities.encodeHex(dtBytes);
- final PayloadBuilder builder = new PayloadBuilder().alertBody("test");
-
- final SimpleApnsNotification fromString = new SimpleApnsNotification(deviceToken, builder.build());
- final SimpleApnsNotification fromBytes = new SimpleApnsNotification(dtBytes, Utilities.toUTF8Bytes(builder.build()));
-
- final String expected = "{\"aps\":{\"alert\":\"test\"}}";
- final int actualPacketLength = 1 + 2 + dtBytes.length + 2 + /* payload length = */ Utilities.toUTF8Bytes(expected).length;
- assertEquals(actualPacketLength, fromString.length());
- assertEquals(actualPacketLength, fromBytes.length());
- assertEquals(expected.length(), fromString.getPayload().length);
- assertArrayEquals(fromString.marshall(), fromBytes.marshall());
- assertFalse(builder.isTooLong());
- }
-
- private String strOfLen(final int l) {
- final StringBuilder sb = new StringBuilder();
- for (int i = 0; i < l; ++i) {
- sb.append('c');
- }
- return sb.toString();
- }
-
- private PayloadBuilder payloadOf(final int l) {
- return APNS.newPayload().alertBody(strOfLen(l));
- }
-
- @Test
- public void detectingLongMessages() {
- final String basic = "{\"aps\":{\"alert\":\"\"}}";
- final int wrapperOverhead = basic.length();
- final int cutoffForAlert = 2048 - wrapperOverhead;
-
- final PayloadBuilder wayShort = payloadOf(1);
- assertFalse(wayShort.isTooLong());
- assertTrue(wayShort.length() == wrapperOverhead + 1);
-
- final PayloadBuilder bitShort = payloadOf(cutoffForAlert - 1);
- assertFalse(bitShort.isTooLong());
- assertTrue(bitShort.length() == wrapperOverhead + cutoffForAlert - 1);
-
- final PayloadBuilder border = payloadOf(cutoffForAlert);
- assertFalse(border.isTooLong());
- assertTrue(border.length() == wrapperOverhead + cutoffForAlert);
- assertTrue(border.length() == 2048);
-
- final PayloadBuilder abitLong = payloadOf(cutoffForAlert + 1);
- assertTrue(abitLong.isTooLong());
- assertTrue(abitLong.length() == wrapperOverhead + cutoffForAlert + 1);
-
- final PayloadBuilder tooLong = payloadOf(cutoffForAlert + 1000);
- assertTrue(tooLong.isTooLong());
- assertTrue(tooLong.length() == wrapperOverhead + cutoffForAlert + 1000);
- }
-
- @Test
- public void shrinkLongMessages() {
- final String basic = "{\"aps\":{\"alert\":\"\"}}";
- final int wrapperOverhead = basic.length();
- final int cutoffForAlert = 2048 - wrapperOverhead;
- final int max_length = 2048;
-
- final PayloadBuilder wayShort = payloadOf(1);
- wayShort.shrinkBody(); // NOOP
- assertFalse(wayShort.isTooLong());
- assertTrue(wayShort.length() == wrapperOverhead + 1);
-
- final PayloadBuilder bitShort = payloadOf(cutoffForAlert - 1);
- bitShort.shrinkBody(); // NOOP
- assertFalse(bitShort.isTooLong());
- assertTrue(bitShort.length() == wrapperOverhead + cutoffForAlert - 1);
-
- final PayloadBuilder border = payloadOf(cutoffForAlert);
- assertFalse(border.isTooLong()); // NOOP
- assertTrue(border.length() == max_length);
-
- final PayloadBuilder abitLong = payloadOf(cutoffForAlert + 1);
- abitLong.shrinkBody();
- assertFalse(abitLong.isTooLong());
- assertTrue(abitLong.length() == max_length);
-
- final PayloadBuilder tooLong = payloadOf(cutoffForAlert + 1000);
- tooLong.shrinkBody();
- assertFalse(tooLong.isTooLong());
- assertTrue(tooLong.length() == max_length);
- }
-
- @Test
- public void shrinkLongMessagesWithOtherthigns() {
- final String basic = "{\"aps\":{\"alert\":\"\"}}";
- final int wrapperOverhead = basic.length();
- final int cutoffForAlert = 2048 - wrapperOverhead;
- final int max_length = 2048;
-
- final PayloadBuilder wayShort = payloadOf(1).sound("default");
- assertFalse(wayShort.isTooLong());
- assertTrue(wayShort.length() <= max_length);
-
- final PayloadBuilder bitShort = payloadOf(cutoffForAlert - 1).sound("default");
- bitShort.shrinkBody(); // NOOP
- assertFalse(bitShort.isTooLong());
- assertTrue(bitShort.length() <= max_length);
-
- final PayloadBuilder border = payloadOf(cutoffForAlert).sound("default");
- border.shrinkBody();
- assertFalse(border.isTooLong()); // NOOP
- assertTrue(border.length() == max_length);
-
- final PayloadBuilder abitLong = payloadOf(cutoffForAlert + 1).sound("default");
- abitLong.shrinkBody();
- assertFalse(abitLong.isTooLong());
- assertTrue(abitLong.length() == max_length);
-
- final PayloadBuilder tooLong = payloadOf(cutoffForAlert + 1000).sound("default");
- tooLong.shrinkBody();
- assertFalse(tooLong.isTooLong());
- assertTrue(tooLong.length() == max_length);
- }
-
- @Test
- public void removeAlertIfSooLong() {
- final PayloadBuilder tooLong =
- APNS.newPayload()
- .customField("test", strOfLen(2048))
- .alertBody("what");
- tooLong.shrinkBody();
- final String payload = tooLong.build();
- assertThat(payload, not(containsString("alert")));
-
- }
-
- private void assertEqualsJson(final String expected, final String actual) {
- final ObjectMapper mapper = new ObjectMapper();
- try {
- @SuppressWarnings("unchecked")
- final
- Map exNode = mapper.readValue(expected, Map.class),
- acNode = mapper.readValue(actual, Map.class);
- assertEquals(exNode, acNode);
- } catch (final Exception e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Test
- public void supportsMDM() {
- final String mdm = APNS.newPayload().mdm("213").toString();
-
- final String expected = "{\"mdm\":\"213\"}";
- assertEqualsJson(expected, mdm);
- }
-
- @Test
- public void supportsNewsstand() {
- final String news = APNS.newPayload().forNewsstand().toString();
-
- final String expected = "{\"aps\":{\"content-available\":1}}";
- assertEqualsJson(expected, news);
- }
-
- @Test
- public void tooLongWithCustomFields() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.alertBody("12345678");
-
- builder.customField("ache1", "what");
- builder.customField("ache2", 2);
-
- final String s1 = builder.toString();
- assertThat(s1, containsString("12345678"));
- final String s2 = builder.toString();
- assertThat(s2, containsString("12345678"));
-
- assertEqualsJson(s1, s2);
- }
-
- @Test
- public void trimWorksWithLongFields() {
- final PayloadBuilder builder = new PayloadBuilder();
- final String toolong =
- "1234567890123456789012345678901234567890" +
- "1234567890123456789012345678901234567890" +
- "1234567890123456789012345678901234567890" +
- "1234567890123456789012345678901234567890" +
- "1234567890123456789012345678901234567890" +
- "1234567890123456789012345678901234567890";
-
- builder.alertBody(toolong);
- builder.actionKey("OK");
-
- builder.shrinkBody();
-
- final String s2 = builder.toString();
- assertThat(s2, containsString("12345678"));
- }
-
-
- @Test
- public void utf8Encoding() {
- final String str = "esem�ny";
-
- final PayloadBuilder builder = new PayloadBuilder();
- final String s1 = builder.alertBody(str).toString();
-
- assertThat(s1, containsString(str));
- }
-
- @Test
- public void utf8EncodingEscaped() {
- final String str = "esem\u00E9ny";
-
- final PayloadBuilder builder = new PayloadBuilder();
- final String s1 = builder.alertBody(str).toString();
-
- assertThat(s1, containsString(str));
- }
-
- @Test
- public void silentPingMessage() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.instantDeliveryOrSilentNotification();
-
- final String expected = "{\"aps\":{\"content-available\":1}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
-
- }
-
- @Test
- public void silentPingMessageWithCustomKey() {
- final PayloadBuilder builder = new PayloadBuilder();
-
- builder.instantDeliveryOrSilentNotification();
- builder.customField("ache1", "what");
-
- final String expected = "{\"aps\":{\"content-available\":1},\"ache1\":\"what\"}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
-
- }
-
- @Test
- public void instantMessageWithAlert() {
- final PayloadBuilder builder = new PayloadBuilder();
- builder.alertBody("test");
- builder.instantDeliveryOrSilentNotification();
-
- final String expected = "{\"aps\":{\"alert\":\"test\",\"content-available\":1}}";
- final String actual = builder.toString();
- assertEqualsJson(expected, actual);
- }
-}
diff --git a/src/test/java/com/notnoop/apns/integration/ApnsConnectionCacheTest.java b/src/test/java/com/notnoop/apns/integration/ApnsConnectionCacheTest.java
deleted file mode 100644
index 79aa042e..00000000
--- a/src/test/java/com/notnoop/apns/integration/ApnsConnectionCacheTest.java
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.integration;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicInteger;
-import com.notnoop.apns.APNS;
-import com.notnoop.apns.ApnsDelegate;
-import com.notnoop.apns.StartSendingApnsDelegate;
-import com.notnoop.apns.ApnsNotification;
-import com.notnoop.apns.ApnsService;
-import com.notnoop.apns.DeliveryError;
-import com.notnoop.apns.EnhancedApnsNotification;
-import com.notnoop.apns.SimpleApnsNotification;
-import com.notnoop.apns.utils.ApnsServerStub;
-import com.notnoop.apns.utils.FixedCertificates;
-import org.junit.*;
-
-import static com.notnoop.apns.utils.FixedCertificates.*;
-
-@SuppressWarnings("deprecation")
-public class ApnsConnectionCacheTest {
-
- private ApnsServerStub server;
- private static SimpleApnsNotification msg1 = new SimpleApnsNotification("a87d8878d878a79", "{\"aps\":{}}");
- private static SimpleApnsNotification msg2 = new SimpleApnsNotification("a87d8878d878a88", "{\"aps\":{}}");
- private static EnhancedApnsNotification eMsg1 = new EnhancedApnsNotification(EnhancedApnsNotification.INCREMENT_ID(),
- 1, "a87d8878d878a88", "{\"aps\":{}}");
- private static EnhancedApnsNotification eMsg2 = new EnhancedApnsNotification(EnhancedApnsNotification.INCREMENT_ID(),
- 1, "a87d8878d878a88", "{\"aps\":{}}");
- private static EnhancedApnsNotification eMsg3 = new EnhancedApnsNotification(EnhancedApnsNotification.INCREMENT_ID(),
- 1, "a87d8878d878a88", "{\"aps\":{}}");
-
- @Before
- public void startup() {
- }
-
- @After
- public void tearDown() {
- server.stop();
- server = null;
- }
-
-
- /**
- * Test1 to make sure that after rejected notification
- * in-flight notifications are re-transmitted
- *
- * @throws InterruptedException
- */
- @Test(timeout = 5000)
- public void handleReTransmissionError5Good1Bad7Good() throws InterruptedException {
-
- server = new ApnsServerStub(FixedCertificates.serverContext().getServerSocketFactory());
- //5 success 1 fail 7 success 7 resent
- final CountDownLatch sync = new CountDownLatch(20);
- final AtomicInteger numResent = new AtomicInteger();
- final AtomicInteger numSent = new AtomicInteger();
- final AtomicInteger numStartSend = new AtomicInteger();
- int EXPECTED_RESEND_COUNT = 7;
- int EXPECTED_SEND_COUNT = 12;
- server.getWaitForError().acquire();
- server.start();
- ApnsService service =
- APNS.newService().withSSLContext(clientContext())
- .withGatewayDestination(LOCALHOST, server.getEffectiveGatewayPort())
- .withDelegate(new StartSendingApnsDelegate() {
-
- public void startSending(final ApnsNotification message, final boolean resent) {
- if (!resent) {
- numStartSend.incrementAndGet();
- }
- }
-
- public void messageSent(ApnsNotification message, boolean resent) {
- if (!resent) {
- numSent.incrementAndGet();
- }
- sync.countDown();
- }
-
- public void messageSendFailed(ApnsNotification message, Throwable e) {
- numSent.decrementAndGet();
- }
-
- public void connectionClosed(DeliveryError e, int messageIdentifier) {
- }
-
- public void cacheLengthExceeded(int newCacheLength) {
- }
-
- public void notificationsResent(int resendCount) {
- numResent.set(resendCount);
- }
- })
- .build();
- server.stopAt(eMsg1.length() * 5 + eMsg2.length() + eMsg3.length() * 14);
- for (int i = 0; i < 5; ++i) {
- service.push(eMsg1);
- }
-
-
- service.push(eMsg2);
-
- for (int i = 0; i < 7; ++i) {
- service.push(eMsg3);
- }
-
- server.sendError(8, eMsg2.getIdentifier());
-
- server.getWaitForError().release();
- server.getMessages().acquire();
-
- sync.await();
-
- Assert.assertEquals(EXPECTED_RESEND_COUNT, numResent.get());
- Assert.assertEquals(EXPECTED_SEND_COUNT, numSent.get());
- Assert.assertEquals(EXPECTED_SEND_COUNT + 1, numStartSend.get());
-
- }
-
- /**
- * Test2 to make sure that after rejected notification
- * in-flight notifications are re-transmitted
- *
- * @throws InterruptedException
- */
- @Test(timeout = 5000)
- public void handleReTransmissionError1Good1Bad2Good() throws InterruptedException {
- server = new ApnsServerStub(FixedCertificates.serverContext().getServerSocketFactory());
- final CountDownLatch sync = new CountDownLatch(6);
- final AtomicInteger numResent = new AtomicInteger();
- final AtomicInteger numSent = new AtomicInteger();
- final AtomicInteger numStartSend = new AtomicInteger();
- int EXPECTED_RESEND_COUNT = 2;
- int EXPECTED_SEND_COUNT = 3;
- server.getWaitForError().acquire();
- server.start();
- ApnsService service =
- APNS.newService().withSSLContext(clientContext())
- .withGatewayDestination(LOCALHOST, server.getEffectiveGatewayPort())
- .withDelegate(new StartSendingApnsDelegate() {
-
- public void startSending(final ApnsNotification message, final boolean resent) {
- if (!resent) {
- numStartSend.incrementAndGet();
- }
- }
-
- public void messageSent(ApnsNotification message, boolean resent) {
- if (!resent) {
- numSent.incrementAndGet();
- }
- sync.countDown();
- }
-
- public void messageSendFailed(ApnsNotification message, Throwable e) {
- numSent.decrementAndGet();
- }
-
- public void connectionClosed(DeliveryError e, int messageIdentifier) {
- }
-
- public void cacheLengthExceeded(int newCacheLength) {
- }
-
- public void notificationsResent(int resendCount) {
- numResent.set(resendCount);
- }
- })
- .build();
- server.stopAt(msg1.length() * 3 + eMsg2.length() * 2);
- service.push(msg1);
- service.push(eMsg2);
- service.push(eMsg1);
- service.push(msg2);
-
- server.sendError(8, eMsg2.getIdentifier());
- server.getWaitForError().release();
- server.getMessages().acquire();
-
- sync.await();
-
- Assert.assertEquals(EXPECTED_RESEND_COUNT, numResent.get());
- Assert.assertEquals(EXPECTED_SEND_COUNT, numSent.get());
- Assert.assertEquals(EXPECTED_SEND_COUNT + 1, numStartSend.get());
-
- }
-
- /**
- * Test to make sure single rejected notifications are returned
- *
- * @throws InterruptedException
- */
- @Test(timeout = 5000)
- public void handleReTransmissionError1Bad() throws InterruptedException {
-
- server = new ApnsServerStub(FixedCertificates.serverContext().getServerSocketFactory());
- final CountDownLatch sync = new CountDownLatch(1);
- final AtomicInteger numError = new AtomicInteger();
- final AtomicInteger numStartSend = new AtomicInteger();
- int EXPECTED_ERROR_COUNT = 1;
- server.getWaitForError().acquire();
- server.start();
- ApnsService service =
- APNS.newService().withSSLContext(clientContext())
- .withGatewayDestination(LOCALHOST, server.getEffectiveGatewayPort())
- .withDelegate(new StartSendingApnsDelegate() {
-
- public void startSending(final ApnsNotification message, final boolean resent) {
- if (!resent) {
- numStartSend.incrementAndGet();
- }
- }
-
- public void messageSent(ApnsNotification message, boolean resent) {
- }
-
- public void messageSendFailed(ApnsNotification message, Throwable e) {
- numError.incrementAndGet();
- sync.countDown();
- }
-
- public void connectionClosed(DeliveryError e, int messageIdentifier) {
- }
-
- public void cacheLengthExceeded(int newCacheLength) {
- }
-
- public void notificationsResent(int resendCount) {
- }
- })
- .build();
- server.stopAt(eMsg1.length());
- service.push(eMsg1);
-
- server.sendError(8, eMsg1.getIdentifier());
- server.getWaitForError().release();
- server.getMessages().acquire();
-
- sync.await();
-
- Assert.assertEquals(EXPECTED_ERROR_COUNT, numError.get());
- Assert.assertEquals(EXPECTED_ERROR_COUNT, numStartSend.get());
- }
-
- /**
- * Test to make sure that after rejected notification
- * in-flight notifications are re-transmitted with a queued connection
- *
- * @throws InterruptedException
- */
- @Ignore("Fails because old ApnsServerStub does not accept() on the connection socket for all the time.")
- @Test(timeout = 10000)
- public void handleTransmissionErrorInQueuedConnection() throws InterruptedException {
- server = new ApnsServerStub(FixedCertificates.serverContext().getServerSocketFactory());
- final AtomicInteger sync = new AtomicInteger(138);
- final AtomicInteger numResent = new AtomicInteger();
- final AtomicInteger numSent = new AtomicInteger();
- server.getWaitForError().acquire();
- server.start();
- ApnsService service =
- APNS.newService().withSSLContext(clientContext())
- .withGatewayDestination(LOCALHOST, server.getEffectiveGatewayPort())
- .asQueued()
- .withDelegate(new ApnsDelegate() {
- public void messageSent(ApnsNotification message, boolean resent) {
- if (!resent) {
- numSent.incrementAndGet();
- }
- sync.getAndDecrement();
- }
-
- public void messageSendFailed(ApnsNotification message, Throwable e) {
- numSent.decrementAndGet();
- sync.incrementAndGet();
- }
-
- public void connectionClosed(DeliveryError e, int messageIdentifier) {
- }
-
- public void cacheLengthExceeded(int newCacheLength) {
- }
-
- public void notificationsResent(int resendCount) {
- numResent.set(resendCount);
- sync.getAndAdd(resendCount);
- }
- })
- .build();
- server.stopAt(eMsg3.length() * 50 + msg1.length() * 3
- + eMsg2.length() * 2 + eMsg1.length() * 85);
- for (int i = 0; i < 50; ++i) {
- service.push(eMsg3);
- }
- service.push(msg1);
- service.push(eMsg2);
- service.push(eMsg1);
- service.push(msg2);
- for (int i = 0; i < 85; ++i) {
- service.push(eMsg1);
- }
-
- server.sendError(8, eMsg2.getIdentifier());
- server.getWaitForError().release();
- server.getMessages().acquire();
-
- while(sync.get() != 0) {
- Thread.yield();
- }
- }
-
- /**
- * Test to make sure that if the cache length is violated we get
- * a notification
- *
- * @throws InterruptedException
- */
- @Test(timeout = 5000)
- public void cacheLengthNotification() throws InterruptedException {
-
- server = new ApnsServerStub(FixedCertificates.serverContext().getServerSocketFactory());
- final CountDownLatch sync = new CountDownLatch(1);
- int ORIGINAL_CACHE_LENGTH = 100;
- final AtomicInteger modifiedCacheLength = new AtomicInteger();
- server.getWaitForError().acquire();
- server.start();
- ApnsService service =
- APNS.newService().withSSLContext(clientContext())
- .withGatewayDestination(LOCALHOST, server.getEffectiveGatewayPort())
- .withDelegate(new ApnsDelegate() {
- public void messageSent(ApnsNotification message, boolean resent) {
-
- }
-
- public void messageSendFailed(ApnsNotification message, Throwable e) {
- }
-
- public void connectionClosed(DeliveryError e, int messageIdentifier) {
- }
-
- public void cacheLengthExceeded(int newCacheLength) {
- modifiedCacheLength.set(newCacheLength);
- sync.countDown();
- }
-
- public void notificationsResent(int resendCount) {
- }
- })
- .build();
- server.stopAt(eMsg1.length() * 5 + eMsg2.length() + eMsg3.length() * 14);
- for (int i = 0; i < 5; ++i) {
- service.push(eMsg1);
- }
-
-
- service.push(eMsg2);
-
- for (int i = 0; i < 101; ++i) {
- service.push(eMsg3);
- }
-
- server.sendError(8, eMsg2.getIdentifier());
-
- server.getWaitForError().release();
- server.getMessages().acquire();
-
- sync.await();
-
-
- Assert.assertTrue(ORIGINAL_CACHE_LENGTH < modifiedCacheLength.get());
- }
-
-}
diff --git a/src/test/java/com/notnoop/apns/integration/ApnsConnectionResendTest.java b/src/test/java/com/notnoop/apns/integration/ApnsConnectionResendTest.java
deleted file mode 100644
index f826146f..00000000
--- a/src/test/java/com/notnoop/apns/integration/ApnsConnectionResendTest.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.integration;
-
-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 com.notnoop.apns.EnhancedApnsNotification;
-import com.notnoop.apns.integration.ApnsDelegateRecorder.MessageSentFailedRecord;
-import com.notnoop.apns.utils.FixedCertificates;
-import com.notnoop.apns.utils.Simulator.ApnsResponse;
-import com.notnoop.apns.utils.Simulator.ApnsSimulatorWithVerification;
-import com.notnoop.exceptions.ApnsDeliveryErrorException;
-import com.notnoop.exceptions.NetworkIOException;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.List;
-
-import static com.notnoop.apns.utils.FixedCertificates.LOCALHOST;
-import static com.notnoop.apns.utils.FixedCertificates.clientContext;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-public class ApnsConnectionResendTest {
-
- private static EnhancedApnsNotification NOTIFICATION_0 = buildNotification(0);
- private static EnhancedApnsNotification NOTIFICATION_1 = buildNotification(1);
- private static EnhancedApnsNotification NOTIFICATION_2 = buildNotification(2);
- private static ApnsSimulatorWithVerification apnsSim;
-
- private ApnsDelegateRecorder delegateRecorder;
- private ApnsService testee;
-
- @Before
- public void setUp() {
- if (apnsSim == null) {
- apnsSim = new ApnsSimulatorWithVerification(FixedCertificates.serverContext().getServerSocketFactory());
- apnsSim.start();
- }
- apnsSim.reset();
- delegateRecorder = new ApnsDelegateRecorder();
- testee = build(delegateRecorder);
- }
-
- @AfterClass
- public static void tearDownClass() {
- if (apnsSim != null) {
- apnsSim.stop();
- apnsSim = null;
- }
- }
-
- /*
- * Test when we submit 3 messages to APNS 0, 1, 2. 0 is an error but we don't see the error response back until
- * 1,2 have already been submitted. Then at this point the network connection to APNS cannot be made, so that
- * when retrying the submissions we have to notify the client that delivery failed for 1 and 2.
- */
- @Test
- public void testGivenFailedSubmissionDueToErrorThenApnsDownWithNotificationsInBufferEnsureClientNotified()
- throws Exception {
-
- final DeliveryError deliveryError = DeliveryError.INVALID_PAYLOAD_SIZE;
-
- apnsSim.when(NOTIFICATION_0).thenDoNothing();
- apnsSim.when(NOTIFICATION_1).thenDoNothing();
- apnsSim.when(NOTIFICATION_2).thenRespond(ApnsResponse.returnErrorAndShutdown(deliveryError, NOTIFICATION_0));
-
- testee.push(NOTIFICATION_0);
- testee.push(NOTIFICATION_1);
- testee.push(NOTIFICATION_2);
-
- // Give some time for connection failure to take place
- Thread.sleep(5000);
- // Verify received expected notifications
- apnsSim.verify();
-
- // verify delegate calls
- assertEquals(3, delegateRecorder.getSent().size());
- final List failed = delegateRecorder.getFailed();
- assertEquals(3, failed.size());
- // first is failed delivery due to payload size
- failed.get(0).assertRecord(NOTIFICATION_0, new ApnsDeliveryErrorException(deliveryError));
- // second and third are due to not being able to connect to APNS
- assertNetworkIoExForRedelivery(NOTIFICATION_1, failed.get(1));
- assertNetworkIoExForRedelivery(NOTIFICATION_2, failed.get(2));
- }
-
- private void assertNetworkIoExForRedelivery(ApnsNotification notification, MessageSentFailedRecord failed) {
- failed.assertRecord(notification, new NetworkIOException());
- final NetworkIOException found = failed.getException();
- assertTrue(found.isResend());
- }
-
-
- private ApnsService build(ApnsDelegate delegate) {
- return APNS.newService()
- .withConnectTimeout(1000)
- .withSSLContext(clientContext())
- .withGatewayDestination(LOCALHOST, apnsSim.getEffectiveGatewayPort())
- .withFeedbackDestination(LOCALHOST, apnsSim.getEffectiveFeedbackPort())
- .withDelegate(delegate).build();
- }
-
- private static EnhancedApnsNotification buildNotification(int id) {
- final String deviceToken = ApnsSimulatorWithVerification.deviceTokenForId(id);
- return new EnhancedApnsNotification(id, 1, deviceToken, "{\"aps\":{}}");
- }
-
-}
diff --git a/src/test/java/com/notnoop/apns/integration/ApnsConnectionTest.java b/src/test/java/com/notnoop/apns/integration/ApnsConnectionTest.java
deleted file mode 100644
index d366e91c..00000000
--- a/src/test/java/com/notnoop/apns/integration/ApnsConnectionTest.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.integration;
-
-import com.notnoop.apns.APNS;
-import com.notnoop.apns.ApnsService;
-import com.notnoop.apns.EnhancedApnsNotification;
-import com.notnoop.apns.SimpleApnsNotification;
-import com.notnoop.apns.utils.ApnsServerStub;
-import com.notnoop.apns.utils.junit.DumpThreadsOnErrorRule;
-import com.notnoop.apns.utils.junit.Repeat;
-import com.notnoop.apns.utils.junit.RepeatRule;
-import com.notnoop.exceptions.NetworkIOException;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-
-import static com.notnoop.apns.utils.FixedCertificates.LOCALHOST;
-import static com.notnoop.apns.utils.FixedCertificates.clientContext;
-import static com.notnoop.apns.utils.FixedCertificates.clientMultiKeyContext;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-
-@SuppressWarnings("ALL")
-public class ApnsConnectionTest {
-
- @Rule
- public TestName testName = new TestName();
-
- @Rule
- public RepeatRule rr = new RepeatRule();
-
- @Rule
- public DumpThreadsOnErrorRule dumpRule = new DumpThreadsOnErrorRule();
-
- ApnsServerStub server;
- static SimpleApnsNotification msg1 = new SimpleApnsNotification("a87d8878d878a79", "{\"aps\":{}}");
- static SimpleApnsNotification msg2 = new SimpleApnsNotification("a87d8878d878a88", "{\"aps\":{}}");
- static EnhancedApnsNotification eMsg1 = new EnhancedApnsNotification(EnhancedApnsNotification.INCREMENT_ID(),
- 1, "a87d8878d878a88", "{\"aps\":{}}");
- static EnhancedApnsNotification eMsg2 = new EnhancedApnsNotification(EnhancedApnsNotification.INCREMENT_ID(),
- 1, "a87d8878d878a88", "{\"aps\":{}}");
- static EnhancedApnsNotification eMsg3 = new EnhancedApnsNotification(EnhancedApnsNotification.INCREMENT_ID(),
- 1, "a87d8878d878a88", "{\"aps\":{}}");
- private int gatewayPort;
-
- @Before
- public void startup() {
- System.out.println("****** "+testName.getMethodName());
- server = ApnsServerStub.prepareAndStartServer();
- gatewayPort = server.getEffectiveGatewayPort();
- }
-
- @After
- public void tearDown() {
- server.stop();
- server = null;
- }
-
- @Repeat(count = 50)
- @Test(timeout = 2000)
- public void sendOneSimple() throws InterruptedException {
- ApnsService service =
- APNS.newService().withSSLContext(clientContext())
- .withGatewayDestination(LOCALHOST, gatewayPort)
- .build();
- server.stopAt(msg1.length());
- service.push(msg1);
- server.getMessages().acquire();
-
- assertArrayEquals(msg1.marshall(), server.getReceived().toByteArray());
- }
-
- @Repeat(count = 50)
- @Test(timeout = 2000)
- public void sendOneQueued() throws InterruptedException {
- ApnsService service =
- APNS.newService().withSSLContext(clientContext())
- .withGatewayDestination(LOCALHOST, gatewayPort)
- .asQueued()
- .build();
- server.stopAt(msg1.length());
- service.push(msg1);
- server.getMessages().acquire();
-
- assertArrayEquals(msg1.marshall(), server.getReceived().toByteArray());
- }
-
-
- @Test
- public void sendOneSimpleWithoutTimeout() throws InterruptedException {
- server.getToWaitBeforeSend().set(2000);
- ApnsService service =
- APNS.newService().withSSLContext(clientContext())
- .withGatewayDestination(LOCALHOST, gatewayPort)
- .withReadTimeout(5000)
- .build();
- server.stopAt(msg1.length());
- service.push(msg1);
- server.getMessages().acquire();
-
- assertArrayEquals(msg1.marshall(), server.getReceived().toByteArray());
- }
-
- /**
- * Unlike in the feedback case, push messages won't expose the socket timeout,
- * as the read is done in a separate monitoring thread.
- *
- * Therefore, normal behavior is expected in this test.
- *
- * @throws InterruptedException
- */
- @Test
- public void sendOneSimpleWithTimeout() throws InterruptedException {
- server.getToWaitBeforeSend().set(5000);
- ApnsService service =
- APNS.newService().withSSLContext(clientContext())
- .withGatewayDestination(LOCALHOST, gatewayPort)
- .withReadTimeout(1000)
- .build();
- server.stopAt(msg1.length());
- service.push(msg1);
- server.getMessages().acquire();
-
- assertArrayEquals(msg1.marshall(), server.getReceived().toByteArray());
- }
-
- @Test(timeout = 2000)
- public void sendOneSimpleMultiKey() throws InterruptedException {
- ApnsService service =
- APNS.newService().withSSLContext(clientMultiKeyContext("notnoop-client"))
- .withGatewayDestination(LOCALHOST, gatewayPort)
- .build();
- server.stopAt(msg1.length());
- service.push(msg1);
- server.getMessages().acquire();
-
- assertArrayEquals(msg1.marshall(), server.getReceived().toByteArray());
- }
-
- @Test(timeout = 2000)
- public void sendOneSimpleClientCertFail() throws InterruptedException {
- ApnsService service =
- APNS.newService().withSSLContext(clientMultiKeyContext("notused"))
- .withGatewayDestination(LOCALHOST, gatewayPort)
- .build();
- server.stopAt(msg1.length());
- try {
- service.push(msg1);
- fail();
- } catch (NetworkIOException e) {
- assertTrue("Expected bad_certifcate exception", e.getMessage().contains("bad_certificate"));
- }
- }
-
-}
diff --git a/src/test/java/com/notnoop/apns/integration/ApnsDelegateRecorder.java b/src/test/java/com/notnoop/apns/integration/ApnsDelegateRecorder.java
deleted file mode 100644
index 1d3cdfba..00000000
--- a/src/test/java/com/notnoop/apns/integration/ApnsDelegateRecorder.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.integration;
-
-import com.notnoop.apns.ApnsDelegate;
-import com.notnoop.apns.ApnsNotification;
-import com.notnoop.apns.DeliveryError;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-
-public class ApnsDelegateRecorder implements ApnsDelegate {
-
- private List sent = new ArrayList();
- private List failed = new ArrayList();
-
- @Override
- public void messageSent(ApnsNotification message, boolean resent) {
- sent.add(new MessageSentRecord(message, resent));
- }
-
- @Override
- public void messageSendFailed(ApnsNotification message, Throwable e) {
- failed.add(new MessageSentFailedRecord(message, e));
- }
-
- @Override
- public void connectionClosed(DeliveryError e, int messageIdentifier) {
- // not stubbed
- }
-
- @Override
- public void cacheLengthExceeded(int newCacheLength) {
- // not stubbed
- }
-
- @Override
- public void notificationsResent(int resendCount) {
- // not stubbed
- }
-
- public List getSent() {
- return Collections.unmodifiableList(sent);
- }
-
- public List getFailed() {
- return Collections.unmodifiableList(failed);
- }
-
- public static class MessageSentRecord {
- private final ApnsNotification notification;
- private final boolean resent;
-
- public MessageSentRecord(ApnsNotification notification, boolean resent) {
- this.notification = notification;
- this.resent = resent;
- }
-
- public ApnsNotification getNotification() {
- return notification;
- }
-
- public boolean isResent() {
- return resent;
- }
- }
-
- public static class MessageSentFailedRecord {
- private final ApnsNotification notification;
- private final Throwable ex;
-
- public MessageSentFailedRecord(ApnsNotification notification, Throwable ex) {
- this.notification = notification;
- this.ex = ex;
- }
-
- public ApnsNotification getNotification() {
- return notification;
- }
-
- @SuppressWarnings("unchecked")
- public T getException() {
- return (T) ex;
- }
-
- public void assertRecord(ApnsNotification notification, Throwable ex) {
- assertEquals(notification, getNotification());
- assertEquals(ex.getClass(), this.ex.getClass());
- }
- }
-
-}
diff --git a/src/test/java/com/notnoop/apns/integration/ApnsSimulatorLongRunningTest.java b/src/test/java/com/notnoop/apns/integration/ApnsSimulatorLongRunningTest.java
deleted file mode 100644
index ec7ceaf1..00000000
--- a/src/test/java/com/notnoop/apns/integration/ApnsSimulatorLongRunningTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.integration;
-
-import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@SuppressWarnings("deprecation")
-public class ApnsSimulatorLongRunningTest extends ApnsSimulatorTestBase {
-
- final Logger logger = LoggerFactory.getLogger(ApnsSimulatorLongRunningTest.class);
-
- @Test
- public void multipleTokensBad_issue145() throws InterruptedException {
- final int rounds = 15;
- for (int i = 0; i < rounds; ++i) {
- logger.debug("*********** "+i);
- send(8, 0);
- assertNumberReceived(2);
- }
-
- }
-
-}
diff --git a/src/test/java/com/notnoop/apns/integration/ApnsSimulatorTest.java b/src/test/java/com/notnoop/apns/integration/ApnsSimulatorTest.java
deleted file mode 100644
index 194f8127..00000000
--- a/src/test/java/com/notnoop/apns/integration/ApnsSimulatorTest.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.integration;
-
-import com.notnoop.apns.DeliveryError;
-import org.junit.Assert;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.Timeout;
-import org.mockito.Matchers;
-import uk.org.lidalia.slf4jext.Level;
-import uk.org.lidalia.slf4jtest.LoggingEvent;
-import uk.org.lidalia.slf4jtest.TestLoggerFactory;
-
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import static org.hamcrest.CoreMatchers.hasItem;
-import static org.hamcrest.CoreMatchers.not;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-@SuppressWarnings("deprecation")
-public class ApnsSimulatorTest extends ApnsSimulatorTestBase {
-
- // final Logger logger = LoggerFactory.getLogger(ApnsSimulatorTest.class);
-
- //@Rule
- //public DumpThreadsOnErrorRule dump = new DumpThreadsOnErrorRule();
-
- @Rule
- public Timeout timeout = new Timeout(5000);
-
-
- @Test
- public void sendOne() throws InterruptedException {
- send(0);
- server.getQueue().poll(5, TimeUnit.SECONDS);
- assertIdle();
- assertDelegateSentCount(1);
- }
-
- @Test
- public void sendThree() throws InterruptedException {
- sendCount(3, 0);
- assertNumberReceived(3);
- assertDelegateSentCount(3);
- }
-
- @Test
- public void sendThousand() throws InterruptedException {
- TestLoggerFactory.getInstance().setPrintLevel(Level.INFO);
- sendCount(1000, 0);
- assertNumberReceived(1000);
- assertDelegateSentCount(1000);
- }
-
-
- @Test
- public void sendDelay() throws InterruptedException {
- send(-3);
- server.getQueue().poll(5, TimeUnit.SECONDS);
- assertIdle();
- assertDelegateSentCount(1);
- }
-
- @Test
- public void testConnectionClose() throws InterruptedException {
- send(8);
- assertNumberReceived(1);
- assertDelegateSentCount(1);
- verify(delegate, times(1)).connectionClosed(Matchers.any(DeliveryError.class), Matchers.anyInt());
- }
-
- @Test
- public void handleRetransmissionWithSeveralOutstandingMessages() throws InterruptedException {
- send(-1, -1, -1, -1, -1, 8, -1, -1, -1, -1, -1, -1, -1);
- assertNumberReceived(13);
- assertDelegateSentCount(13 + 7); // Initially sending all 13 notifications, then resend the last 7 ones
- verify(delegate, times(1)).connectionClosed(Matchers.any(DeliveryError.class), Matchers.anyInt());
- }
-
-
- @Test
- public void testClientDoesNotResendMessagesWhenServerClosesSocketWithoutErrorPacket() throws InterruptedException {
- send(-1, -1, -1, -1, -1, -100, -1, -1, -1, -1, -1, -1, -1);
- assertNumberReceived(6);
- }
-
- @Ignore
- @Test
- public void RaceCondition() {
- // TODO implement test & decide if fix is necessary afterwards.
- Assert.fail("Assumption: monitoring thread crashes in read() when the sender thread closes the connection first.");
- // Thus the last feedback message gets lost, thus we lose messages.
- }
-
- @Test
- public void abortNoWait() throws InterruptedException {
- send(8, 0);
- assertNumberReceived(2);
- }
-
- @Test
- public void doNotSpamLogWhenConnectionClosesBetweenFeedbackPackets() throws InterruptedException {
- // Don't spam a lot of information into the log when the socket closes at a "legal" location. (Just before
- // or after a feedback packet)
- send(-1, 8, -1);
- assertNumberReceived(3);
- final List allLoggingEvents = TestLoggerFactory.getAllLoggingEvents();
- assertThat(allLoggingEvents, not(hasItem(eventContains("Exception while waiting for error code"))));
- }
-
- @Test
- public void firstTokenBad_issue145() throws InterruptedException {
- // Test for Issue #145
- send(8, 0);
- assertNumberReceived(2);
- }
-}
diff --git a/src/test/java/com/notnoop/apns/integration/ApnsSimulatorTestBase.java b/src/test/java/com/notnoop/apns/integration/ApnsSimulatorTestBase.java
deleted file mode 100644
index 5461924a..00000000
--- a/src/test/java/com/notnoop/apns/integration/ApnsSimulatorTestBase.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.integration;
-
-import com.notnoop.apns.*;
-import com.notnoop.apns.internal.Utilities;
-import com.notnoop.apns.utils.FixedCertificates;
-import com.notnoop.apns.utils.Simulator.ApnsServerSimulator;
-import com.notnoop.apns.utils.Simulator.FailingApnsServerSimulator;
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.rules.TestName;
-import org.mockito.Matchers;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import uk.org.lidalia.slf4jext.Level;
-import uk.org.lidalia.slf4jtest.LoggingEvent;
-import uk.org.lidalia.slf4jtest.TestLoggerFactory;
-
-import java.util.Random;
-import java.util.concurrent.TimeUnit;
-
-import static com.notnoop.apns.utils.FixedCertificates.LOCALHOST;
-import static com.notnoop.apns.utils.FixedCertificates.clientContext;
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-public class ApnsSimulatorTestBase {
- final Logger logger = LoggerFactory.getLogger(ApnsSimulatorTestBase.class);
-
- private static final String payload = "{\"aps\":{}}";
- @Rule
- public TestName name = new TestName();
- protected FailingApnsServerSimulator server;
- protected ApnsDelegate delegate;
- private ApnsService service;
- private Random random;
-
- @Before
- public void startup() {
- // http://projects.lidalia.org.uk/slf4j-test/
- TestLoggerFactory.getInstance().setPrintLevel(Level.DEBUG);
- TestLoggerFactory.clearAll();
-
- logger.info("\n\n\n\n\n");
- logger.info("********* Test: {}", name.getMethodName());
-
- server = new FailingApnsServerSimulator(FixedCertificates.serverContext().getServerSocketFactory());
- server.start();
- delegate = ApnsDelegate.EMPTY;
- delegate = mock(ApnsDelegate.class);
- service = APNS.newService()
- .withSSLContext(clientContext())
- .withGatewayDestination(LOCALHOST, server.getEffectiveGatewayPort())
- .withFeedbackDestination(LOCALHOST, server.getEffectiveFeedbackPort())
- .withDelegate(delegate).build();
- random = new Random();
- }
-
- @After
- public void tearDown() {
- server.stop();
- server = null;
- }
-
- protected Matcher super LoggingEvent> eventContains(final String subString) {
- return new BaseMatcher() {
- @Override
- public boolean matches(final Object item) {
- final String message = ((LoggingEvent) item).getMessage();
- return message.contains(subString);
- }
-
- @Override
- public void describeTo(final Description description) {
- description.appendText("substring [" + subString + "]");
- }
- };
- }
-
- protected void send(final int... codes) {
- for (int code : codes) {
- send(code);
- }
- }
-
- protected void send(final int code) {
-
- ApnsNotification notification = makeNotification(code);
- service.push(notification);
-
- }
-
- /**
- * Create an APNS notification that creates specified "error" behaviour in the
- * {@link com.notnoop.apns.utils.Simulator.FailingApnsServerSimulator}
- *
- * @param code A code specifying the FailingApnsServer's behaviour.
- *
- * - -100: Drop connection
- * - below zero: wait (-code) number times a tenth of a second
- * - above zero: send code as APNS error message then drop connection
- *
- * @return an APNS notification
- */
- private EnhancedApnsNotification makeNotification(final int code) {
- byte[] deviceToken = new byte[32];
- random.nextBytes(deviceToken);
- if (code == 0) {
- deviceToken[0] = 42;
- } else {
- deviceToken[0] = (byte) 0xff;
- deviceToken[1] = (byte) 0xff;
-
- if (code < -100) {
- // Drop connection
- deviceToken[2] = (byte) 2;
- } else if (code < 0) {
- // Sleep
- deviceToken[2] = (byte) 1;
- deviceToken[3] = (byte) -code;
- } else {
- // Send APNS error response then drop connection
- assert code > 0;
- deviceToken[2] = (byte) 0;
- deviceToken[3] = (byte) code;
-
- }
-
- }
- return new EnhancedApnsNotification(EnhancedApnsNotification.INCREMENT_ID(), 1, deviceToken, Utilities.toUTF8Bytes(payload));
- }
-
- protected void sendCount(final int count, final int code) {
- for (int i = 0; i < count; ++i) {
- send(code);
- }
- }
-
- protected void assertNumberReceived(final int count) throws InterruptedException {
- logger.debug("assertNumberReceived {}", count);
- int i = 0;
- try {
- for (; i < count; ++i) {
- ApnsServerSimulator.Notification notification = server.getQueue().poll(5, TimeUnit.SECONDS);
- logger.debug("Polled notification {}", notification);
- if (notification == null)
- throw new RuntimeException("poll timed out");
- }
- } catch (RuntimeException re) {
- logger.error("Exception in assertNumberReceived, took {}", i);
- throw re;
- }
- logger.debug("assertNumberReceived - successfully took {}", count);
- assertIdle();
- }
-
- protected void assertIdle() throws InterruptedException {
- logger.info("assertIdle");
- Thread.sleep(1000);
- assertThat(server.getQueue().size(), equalTo(0));
- }
-
- protected void assertDelegateSentCount(final int count) {
- logger.info("assertDelegateSentCount {}", count);
- verify(delegate, times(count)).messageSent(Matchers.any(ApnsNotification.class), Matchers.anyBoolean());
- }
-}
diff --git a/src/test/java/com/notnoop/apns/integration/FeedbackTest.java b/src/test/java/com/notnoop/apns/integration/FeedbackTest.java
deleted file mode 100644
index 706bee06..00000000
--- a/src/test/java/com/notnoop/apns/integration/FeedbackTest.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.integration;
-
-import java.io.IOException;
-import java.net.SocketTimeoutException;
-import javax.net.ssl.SSLContext;
-import com.notnoop.apns.APNS;
-import com.notnoop.apns.ApnsService;
-import com.notnoop.apns.utils.ApnsServerStub;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import static com.notnoop.apns.internal.ApnsFeedbackParsingUtils.*;
-import static com.notnoop.apns.utils.FixedCertificates.*;
-import static org.junit.Assert.*;
-
-public class FeedbackTest {
-
- ApnsServerStub server;
- SSLContext clientContext = clientContext();
-
-
- @Before
- public void startup() {
- server = ApnsServerStub.prepareAndStartServer();
- }
-
- @After
- public void tearDown() {
- server.stop();
- server = null;
- }
-
- @Test
- public void simpleFeedback() throws IOException {
- server.getToSend().write(simple);
-
- ApnsService service =
- APNS.newService().withSSLContext(clientContext)
- .withGatewayDestination(LOCALHOST, server.getEffectiveGatewayPort())
- .withFeedbackDestination(LOCALHOST, server.getEffectiveFeedbackPort())
- .build();
-
- checkParsedSimple(service.getInactiveDevices());
- }
-
- @Test
- public void simpleFeedbackWithoutTimeout() throws IOException {
- server.getToSend().write(simple);
- server.getToWaitBeforeSend().set(2000);
- ApnsService service =
- APNS.newService().withSSLContext(clientContext)
- .withGatewayDestination(LOCALHOST, server.getEffectiveGatewayPort())
- .withFeedbackDestination(LOCALHOST, server.getEffectiveFeedbackPort())
- .withReadTimeout(3000)
- .build();
-
- checkParsedSimple(service.getInactiveDevices());
- }
-
- @Test()
- public void simpleFeedbackWithTimeout() throws IOException {
- server.getToSend().write(simple);
- server.getToWaitBeforeSend().set(5000);
- ApnsService service =
- APNS.newService().withSSLContext(clientContext)
- .withGatewayDestination(LOCALHOST, server.getEffectiveGatewayPort())
- .withFeedbackDestination(LOCALHOST, server.getEffectiveFeedbackPort())
- .withReadTimeout(1000)
- .build();
- try {
- service.getInactiveDevices();
- fail("RuntimeException expected");
- }
- catch(RuntimeException e) {
- assertEquals("Socket timeout exception expected",
- SocketTimeoutException.class, e.getCause().getClass() );
- }
- }
-
- @Test
- public void threeFeedback() throws IOException {
- server.getToSend().write(three);
-
- ApnsService service =
- APNS.newService().withSSLContext(clientContext)
- .withGatewayDestination(LOCALHOST, server.getEffectiveGatewayPort())
- .withFeedbackDestination(LOCALHOST, server.getEffectiveFeedbackPort())
- .build();
-
- checkParsedThree(service.getInactiveDevices());
- }
-
- @Test
- public void simpleQueuedFeedback() throws IOException {
- server.getToSend().write(simple);
-
- ApnsService service =
- APNS.newService().withSSLContext(clientContext)
- .withGatewayDestination(LOCALHOST, server.getEffectiveGatewayPort())
- .withFeedbackDestination(LOCALHOST, server.getEffectiveFeedbackPort())
- .asQueued()
- .build();
-
- checkParsedSimple(service.getInactiveDevices());
- }
-
- @Test
- public void threeQueuedFeedback() throws IOException {
- server.getToSend().write(three);
-
- ApnsService service =
- APNS.newService().withSSLContext(clientContext)
- .withGatewayDestination(LOCALHOST, server.getEffectiveGatewayPort())
- .withFeedbackDestination(LOCALHOST, server.getEffectiveFeedbackPort())
- .asQueued()
- .build();
-
- checkParsedThree(service.getInactiveDevices());
- }
-
-}
diff --git a/src/test/java/com/notnoop/apns/internal/ApnsConnectionTest.java b/src/test/java/com/notnoop/apns/internal/ApnsConnectionTest.java
deleted file mode 100644
index e9964589..00000000
--- a/src/test/java/com/notnoop/apns/internal/ApnsConnectionTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import java.io.ByteArrayOutputStream;
-import javax.net.SocketFactory;
-import com.notnoop.apns.SimpleApnsNotification;
-import org.junit.Assert;
-import org.junit.Ignore;
-import org.junit.Test;
-import static com.notnoop.apns.internal.MockingUtils.*;
-
-
-@SuppressWarnings("deprecation")
-public class ApnsConnectionTest {
- private SimpleApnsNotification msg = new SimpleApnsNotification ("a87d8878d878a79", "{\"aps\":{}}");
-
- @Test
- public void simpleSocket() {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- SocketFactory factory = mockSocketFactory(baos, null);
- packetSentRegardless(factory, baos);
- }
-
- @Test
- @Ignore
- public void closedSocket() {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- SocketFactory factory = mockClosedThenOpenSocket(baos, null, true, 1);
- packetSentRegardless(factory, baos);
- }
-
- @Test
- public void errorOnce() {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- SocketFactory factory = mockClosedThenOpenSocket(baos, null, false, 1);
- packetSentRegardless(factory, baos);
- }
-
- @Test
- public void errorTwice() {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- SocketFactory factory = mockClosedThenOpenSocket(baos, null, false, 2);
- packetSentRegardless(factory, baos);
- }
-
- /**
- * Connection fails after three retries
- */
- @Test(expected = Exception.class)
- public void errorThrice() {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- SocketFactory factory = mockClosedThenOpenSocket(baos, null, false, 3);
- packetSentRegardless(factory, baos);
- }
-
- private void packetSentRegardless(SocketFactory sf, ByteArrayOutputStream baos) {
- ApnsConnectionImpl connection = new ApnsConnectionImpl(sf, "localhost", 80);
- connection.DELAY_IN_MS = 0;
- connection.sendMessage(msg);
- Assert.assertArrayEquals(msg.marshall(), baos.toByteArray());
- connection.close();
- }
-}
diff --git a/src/test/java/com/notnoop/apns/internal/ApnsFeedbackConnectionTest.java b/src/test/java/com/notnoop/apns/internal/ApnsFeedbackConnectionTest.java
deleted file mode 100644
index 537ddd22..00000000
--- a/src/test/java/com/notnoop/apns/internal/ApnsFeedbackConnectionTest.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-
-import javax.net.SocketFactory;
-
-import org.junit.Test;
-
-import static com.notnoop.apns.internal.ApnsFeedbackParsingUtils.*;
-import static com.notnoop.apns.internal.MockingUtils.mockClosedThenOpenSocket;
-
-public class ApnsFeedbackConnectionTest {
-
- InputStream simpleStream = new ByteArrayInputStream(simple);
- InputStream threeStream = new ByteArrayInputStream(three);
-
- /** Simple Parsing **/
- @Test
- public void rowParseOneDevice() {
- checkRawSimple(Utilities.parseFeedbackStreamRaw(simpleStream));
- }
-
- @Test
- public void threeParseTwoDevices() {
- checkRawThree(Utilities.parseFeedbackStreamRaw(threeStream));
- }
-
- @Test
- public void parsedSimple() {
- checkParsedSimple(Utilities.parseFeedbackStream(simpleStream));
- }
-
- @Test
- public void parsedThree() {
- checkParsedThree(Utilities.parseFeedbackStream(threeStream));
- }
-
- /** With Connection **/
- @Test
- public void connectionParsedOne() {
- SocketFactory sf = MockingUtils.mockSocketFactory(null, simpleStream);
- ApnsFeedbackConnection connection = new ApnsFeedbackConnection(sf, "localhost", 80);
- checkParsedSimple(connection.getInactiveDevices());
- }
-
- @Test
- public void connectionParsedThree() {
- SocketFactory sf = MockingUtils.mockSocketFactory(null, threeStream);
- ApnsFeedbackConnection connection = new ApnsFeedbackConnection(sf, "localhost", 80);
- checkParsedThree(connection.getInactiveDevices());
- }
-
- /** Check error recover **/
- @Test
- public void feedbackWithClosedSocket() {
- SocketFactory sf = mockClosedThenOpenSocket(null, simpleStream, true, 1);
- ApnsFeedbackConnection connection = new ApnsFeedbackConnection(sf, "localhost", 80);
- connection.DELAY_IN_MS = 0;
- checkParsedSimple(connection.getInactiveDevices());
- }
-
- @Test
- public void feedbackWithErrorOnce() {
- SocketFactory sf = mockClosedThenOpenSocket(null, simpleStream, true, 2);
- ApnsFeedbackConnection connection = new ApnsFeedbackConnection(sf, "localhost", 80);
- connection.DELAY_IN_MS = 0;
- checkParsedSimple(connection.getInactiveDevices());
- }
-
- /**
- * Connection fails after three retries
- */
- @Test(expected = Exception.class)
- public void feedbackWithErrorTwice() {
- SocketFactory sf = mockClosedThenOpenSocket(null, simpleStream, true, 3);
- ApnsFeedbackConnection connection = new ApnsFeedbackConnection(sf, "localhost", 80);
- connection.DELAY_IN_MS = 0;
- checkParsedSimple(connection.getInactiveDevices());
- }
-
-}
diff --git a/src/test/java/com/notnoop/apns/internal/ApnsFeedbackParsingUtils.java b/src/test/java/com/notnoop/apns/internal/ApnsFeedbackParsingUtils.java
deleted file mode 100644
index 40603b6f..00000000
--- a/src/test/java/com/notnoop/apns/internal/ApnsFeedbackParsingUtils.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Map;
-import java.util.Random;
-import static org.hamcrest.CoreMatchers.*;
-import static org.junit.Assert.*;
-
-public class ApnsFeedbackParsingUtils {
- static byte[] pack(byte[]... args) {
- int total = 0;
- for (byte[] arg : args)
- total += arg.length;
-
- byte[] result = new byte[total];
-
- int index = 0;
- for (byte[] arg : args) {
- System.arraycopy(arg, 0, result, index, arg.length);
- index += arg.length;
- }
- return result;
- }
-
- static byte[] simpleDevice = new byte[32];
- static byte[] firstDevice = new byte[32];
- static byte[] secondDevice = new byte[32];
- static byte[] thirdDevice = new byte[32];
- static {
- Random random = new Random();
- do {
- random.nextBytes(simpleDevice);
- random.nextBytes(firstDevice);
- random.nextBytes(secondDevice);
- random.nextBytes(thirdDevice);
- } while (Arrays.equals(firstDevice, secondDevice)
- || (Arrays.equals(secondDevice, thirdDevice))
- || (Arrays.equals(firstDevice, thirdDevice)));
- }
-
- static int simpleDate;
- public static byte[] simple = pack(
- /* time_t */ new byte[] {0, 0, 0, 0},
- /* length */ new byte[] { 0, 32 },
- /* device token */ simpleDevice
- );
-
- static int firstDate = 10;
- static int secondDate = 1 << 8;
- static int thirdDate = secondDate;
- public static byte[] three = pack(
- /* first message */
- /* time_t */ new byte[] {0, 0, 0, 10},
- /* length */ new byte[] { 0, 32 },
- /* device token */ firstDevice,
-
- /* second device */
- /* time_t */ new byte[] {0, 0, 1, 0},
- /* length */ new byte[] { 0, 32 },
- /* device token */ secondDevice,
-
- /* Duplicate time */
- /* time_t */ new byte[] {0, 0, 1, 0},
- /* length */ new byte[] { 0, 32 },
- /* device token */ thirdDevice
- );
-
- protected static void checkRawSimple(Map simpleParsed) {
- assertEquals(1, simpleParsed.size());
- assertThat(simpleParsed.keySet(), hasItem(simpleDevice));
-
- for (Map.Entry e : simpleParsed.entrySet()) {
- byte[] device = e.getKey();
- Integer date = e.getValue();
- if (Arrays.equals(simpleDevice, device)) {
- assertEquals(simpleDate, (int)date);
- } else {
- fail("Unexpected value in collection");
- }
- }
- }
-
- protected static void checkRawThree(Map threeParsed) {
- assertEquals(3, threeParsed.size());
- Collection devices = threeParsed.keySet();
- assertThat(devices, hasItems(firstDevice, secondDevice, thirdDevice));
-
- for (Map.Entry e : threeParsed.entrySet()) {
- byte[] device = e.getKey();
- Integer date = e.getValue();
- if (Arrays.equals(firstDevice, device)) {
- assertEquals(firstDate, (int)date);
- } else if (Arrays.equals(secondDevice, device)) {
- assertEquals(secondDate, (int)date);
- } else if (Arrays.equals(thirdDevice, device)) {
- assertEquals(thirdDate, (int)date);
- } else {
- fail("Unexpected value in collection");
- }
- }
-
- }
-
- public static void checkParsedSimple(Map simpleParsed) {
- Date sd = new Date(simpleDate * 1000L);
- String deviceToken = Utilities.encodeHex(simpleDevice);
-
- assertEquals(1, simpleParsed.size());
- assertThat(simpleParsed.keySet(), hasItem(deviceToken));
- assertEquals(sd, simpleParsed.get(deviceToken));
- }
-
- public static void checkParsedThree(Map threeParsed) {
- Date d1 = new Date(firstDate * 1000L);
- String dt1 = Utilities.encodeHex(firstDevice);
-
- Date d2 = new Date(secondDate * 1000L);
- String dt2 = Utilities.encodeHex(secondDevice);
-
- Date d3 = new Date(thirdDate * 1000L);
- String dt3 = Utilities.encodeHex(thirdDevice);
-
- assertEquals(3, threeParsed.size());
- assertThat(threeParsed.keySet(), hasItems(dt1, dt2, dt3));
- assertEquals(d1, threeParsed.get(dt1));
- assertEquals(d2, threeParsed.get(dt2));
- assertEquals(d3, threeParsed.get(dt3));
- }
-
-}
diff --git a/src/test/java/com/notnoop/apns/internal/ApnsPooledConnectionTest.java b/src/test/java/com/notnoop/apns/internal/ApnsPooledConnectionTest.java
deleted file mode 100644
index 7071a85b..00000000
--- a/src/test/java/com/notnoop/apns/internal/ApnsPooledConnectionTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import com.notnoop.apns.ApnsNotification;
-import com.notnoop.exceptions.NetworkIOException;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-import static org.mockito.Mockito.*;
-
-public class ApnsPooledConnectionTest {
-
- private ApnsConnection errorPrototype;
- private ApnsConnection prototype;
-
- private ExecutorService executorService;
-
- @Before
- public void setup() {
- errorPrototype = mock(ApnsConnection.class);
- when(errorPrototype.copy()).thenReturn(errorPrototype);
- doThrow(NetworkIOException.class).when(errorPrototype).sendMessage(any(ApnsNotification.class));
-
- prototype = mock(ApnsConnection.class);
- when(prototype.copy()).thenReturn(prototype);
- }
-
- @After
- public void cleanup() {
- if (executorService != null) {
- executorService.shutdownNow();
- }
- }
-
- @Test(expected = NetworkIOException.class)
- public void testSendMessage() throws Exception {
- ApnsPooledConnection conn = new ApnsPooledConnection(errorPrototype, 1, getSingleThreadExecutor());
- conn.sendMessage(mock(ApnsNotification.class));
- }
-
- @Test
- public void testCopyCalls() throws Exception {
- ApnsPooledConnection conn = new ApnsPooledConnection(prototype, 1, getSingleThreadExecutor());
- for (int i = 0; i < 10; i++) {
- conn.sendMessage(mock(ApnsNotification.class));
- }
- verify(prototype, times(1)).copy();
- }
-
- @Test
- public void testCloseCalls() throws Exception {
- ApnsPooledConnection conn = new ApnsPooledConnection(prototype, 1, getSingleThreadExecutor());
- conn.sendMessage(mock(ApnsNotification.class));
- conn.close();
- // should be closed twice because of the thread local copy
- verify(prototype, times(2)).close();
- }
-
- private ExecutorService getSingleThreadExecutor() {
- executorService = Executors.newSingleThreadExecutor();
- return executorService;
- }
-}
\ No newline at end of file
diff --git a/src/test/java/com/notnoop/apns/internal/ApnsServiceImplTest.java b/src/test/java/com/notnoop/apns/internal/ApnsServiceImplTest.java
deleted file mode 100644
index e4b60ebf..00000000
--- a/src/test/java/com/notnoop/apns/internal/ApnsServiceImplTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import org.junit.Test;
-import static org.mockito.Mockito.*;
-
-import com.notnoop.apns.ApnsService;
-import com.notnoop.apns.EnhancedApnsNotification;
-
-public class ApnsServiceImplTest {
-
- EnhancedApnsNotification notification = new EnhancedApnsNotification(1,
- EnhancedApnsNotification.MAXIMUM_EXPIRY, "2342", "{}");
-
- @Test
- public void pushEventually() {
- ApnsConnection connection = mock(ApnsConnection.class);
- ApnsService service = newService(connection, null);
-
- service.push(notification);
-
- verify(connection, times(1)).sendMessage(notification);
- }
-
- @Test
- public void pushEventuallySample() {
- ApnsConnection connection = mock(ApnsConnection.class);
- ApnsService service = newService(connection, null);
-
- service.push("2342", "{}");
-
- verify(connection, times(1)).sendMessage(notification);
- }
-
- protected ApnsService newService(ApnsConnection connection, ApnsFeedbackConnection feedback) {
- return new ApnsServiceImpl(connection, null);
- }
-}
diff --git a/src/test/java/com/notnoop/apns/internal/BatchApnsServiceTest.java b/src/test/java/com/notnoop/apns/internal/BatchApnsServiceTest.java
deleted file mode 100644
index 70b62030..00000000
--- a/src/test/java/com/notnoop/apns/internal/BatchApnsServiceTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.io.IOException;
-import java.util.concurrent.Executors;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import com.notnoop.apns.ApnsNotification;
-
-public class BatchApnsServiceTest {
-
- private ApnsConnection prototype;
- private BatchApnsService service;
-
- private int delayTimeInSec = 2;
- private int delayTimeInSec_millis = delayTimeInSec * 1000; /* 2000 */
- private int delayTimeInSec1_2_millis = delayTimeInSec * 1000 / 2; /* 1000 */
- private int delayTimeInSec1_4_millis = delayTimeInSec * 1000 / 4; /* 500 */
- private int maxDelayTimeInSec = 2 * delayTimeInSec;
-
- @Before
- public void setup() {
- prototype = mock(ApnsConnection.class);
- when(prototype.copy()).thenReturn(prototype);
-
- service = new BatchApnsService(prototype, null, delayTimeInSec, maxDelayTimeInSec, Executors.defaultThreadFactory());
- }
-
- @Test
- public void simpleBatchWait_one() throws IOException, InterruptedException {
- // send message
- ApnsNotification message = service.push("1234", "{}");
-
- // make sure no message was send yet
- verify(prototype, times(0)).copy();
- verify(prototype, times(0)).sendMessage(message);
- verify(prototype, times(0)).close();
-
- Thread.sleep(delayTimeInSec_millis + /* for sure */250);
-
- // verify batch sends and close the connection
- verify(prototype, times(1)).copy();
- verify(prototype, times(1)).sendMessage(message);
- verify(prototype, times(1)).close();
- }
-
- @Test
- public void simpleBatchWait_multiple() throws IOException, InterruptedException {
- // send message
- ApnsNotification message1 = service.push("1234", "{}");
- Thread.sleep(delayTimeInSec1_2_millis);
- ApnsNotification message2 = service.push("4321", "{}");
-
- // make sure no message was send yet
- verify(prototype, times(0)).copy();
- verify(prototype, times(0)).sendMessage(message1);
- verify(prototype, times(0)).sendMessage(message2);
- verify(prototype, times(0)).close();
-
- Thread.sleep(delayTimeInSec1_4_millis * 3);
-
- // still no send
- verify(prototype, times(0)).copy();
- verify(prototype, times(0)).sendMessage(message1);
- verify(prototype, times(0)).sendMessage(message2);
- verify(prototype, times(0)).close();
-
- Thread.sleep(delayTimeInSec1_4_millis + /* for sure */250);
-
- // verify batch sends and close the connection
- verify(prototype, times(1)).copy();
- verify(prototype, times(1)).sendMessage(message1);
- verify(prototype, times(1)).sendMessage(message2);
- verify(prototype, times(1)).close();
- }
-
- @Test
- public void simpleBatchWait_maxDelay() throws IOException, InterruptedException {
- // send message
- ApnsNotification message1 = service.push("1234", "{}");
- Thread.sleep(delayTimeInSec1_4_millis * 3);
- ApnsNotification message2 = service.push("4321", "{}");
- Thread.sleep(delayTimeInSec1_4_millis * 3);
- ApnsNotification message3 = service.push("4321", "{}");
- Thread.sleep(delayTimeInSec1_4_millis * 3);
- ApnsNotification message4 = service.push("4321", "{}");
-
- // make sure no message was send yet
- verify(prototype, times(0)).copy();
- verify(prototype, times(0)).sendMessage(message1);
- verify(prototype, times(0)).sendMessage(message2);
- verify(prototype, times(0)).sendMessage(message3);
- verify(prototype, times(0)).sendMessage(message4);
- verify(prototype, times(0)).close();
-
- Thread.sleep(delayTimeInSec1_4_millis + /* for sure */250);
-
- // verify batch sends and close the connection
- verify(prototype, times(1)).copy();
- verify(prototype, times(1)).sendMessage(message1);
- verify(prototype, times(1)).sendMessage(message2);
- verify(prototype, times(1)).sendMessage(message3);
- verify(prototype, times(1)).sendMessage(message4);
- verify(prototype, times(1)).close();
- }
-
-}
diff --git a/src/test/java/com/notnoop/apns/internal/MockingUtils.java b/src/test/java/com/notnoop/apns/internal/MockingUtils.java
deleted file mode 100644
index 0b1b3e81..00000000
--- a/src/test/java/com/notnoop/apns/internal/MockingUtils.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.Socket;
-import java.util.ArrayList;
-import java.util.List;
-import javax.net.SocketFactory;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-import org.mockito.stubbing.OngoingStubbing;
-
-import static org.mockito.Mockito.*;
-
-public class MockingUtils {
-
- static SocketFactory mockSocketFactory(OutputStream out, InputStream in) {
- try {
- Socket socket = mock(Socket.class);
- when(socket.getOutputStream()).thenReturn(out);
- when(socket.getInputStream()).thenReturn(in);
-
- SocketFactory factory = mock(SocketFactory.class);
- when(factory.createSocket()).thenReturn(socket);
- when(factory.createSocket(anyString(), anyInt())).thenReturn(socket);
-
- return factory;
- } catch (Exception e) {
- e.printStackTrace();
- throw new AssertionError("Cannot be here!");
- }
- }
-
- static SocketFactory mockClosedThenOpenSocket(OutputStream out, InputStream in, boolean isClosed, int failedTries) {
- try {
- List socketMocks = new ArrayList(failedTries + 1);
-
- for (int i = 0; i < failedTries; ++i) {
- Socket socket = mock(Socket.class);
- if (isClosed) {
- mockSocketClosed(socket);
- } else {
- when(socket.getOutputStream()).thenThrow(
- new IOException("simulated IOException"));
- doAnswer(new DynamicMockSocketClosed(socket)).when(socket).close();
- }
- socketMocks.add(socket);
- }
-
- Socket socket = mock(Socket.class);
- when(socket.getOutputStream()).thenReturn(out);
- when(socket.getInputStream()).thenReturn(in);
- when(socket.isConnected()).thenReturn(true);
- socketMocks.add(socket);
-
- SocketFactory factory = mock(SocketFactory.class);
- OngoingStubbing stubbing = when(factory.createSocket(anyString(), anyInt()));
- for (Socket t : socketMocks)
- stubbing = stubbing.thenReturn(t);
-
- return factory;
- } catch (Exception e) {
- e.printStackTrace();
- throw new AssertionError("Cannot be here!");
- }
- }
-
- private static void mockSocketClosed(final Socket socket) throws IOException {
- when(socket.isClosed()).thenReturn(true);
- when(socket.isConnected()).thenReturn(false);
- when(socket.getOutputStream()).thenThrow(
- new AssertionError("Should have checked for closed connection"));
- }
-
- /**
- * Change a mock socket's behaviour to be closed. Dynamically used from close()
- */
- private static class DynamicMockSocketClosed implements Answer {
- private final Socket socket;
-
- public DynamicMockSocketClosed(final Socket socket) {
- this.socket = socket;
- }
-
- @Override
- public Void answer(final InvocationOnMock invocation) throws Throwable {
- mockSocketClosed(socket);
- return null;
- }
- }
-}
diff --git a/src/test/java/com/notnoop/apns/internal/QueuedApnsServiceTCTest.java b/src/test/java/com/notnoop/apns/internal/QueuedApnsServiceTCTest.java
deleted file mode 100644
index d7374649..00000000
--- a/src/test/java/com/notnoop/apns/internal/QueuedApnsServiceTCTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import static org.junit.Assert.*;
-
-import org.junit.Test;
-import static org.mockito.Mockito.*;
-
-import com.notnoop.apns.ApnsService;
-import com.notnoop.apns.SimpleApnsNotification;
-import com.notnoop.apns.internal.QueuedApnsServiceTest.ConnectionStub;
-
-public class QueuedApnsServiceTCTest {
-
- @Test(expected=IllegalStateException.class)
- public void sendWithoutStarting() {
- QueuedApnsService service = new QueuedApnsService(null);
- service.push(notification);
- }
-
- SimpleApnsNotification notification = new SimpleApnsNotification("2342", "{}");
-
- @Test
- public void pushEventually() {
- ConnectionStub connection = spy(new ConnectionStub(0, 1));
- ApnsService service = newService(connection, null);
-
- service.push(notification);
- connection.semaphore.acquireUninterruptibly();
-
- verify(connection, times(1)).sendMessage(notification);
- }
-
- @Test
- public void doNotBlock() {
- final int delay = 10000;
- ConnectionStub connection = spy(new ConnectionStub(delay, 2));
- QueuedApnsService queued =
- new QueuedApnsService(new ApnsServiceImpl(connection, null));
- queued.start();
- long time1 = System.currentTimeMillis();
- queued.push(notification);
- queued.push(notification);
- long time2 = System.currentTimeMillis();
- assertTrue("queued.push() blocks", (time2 - time1) < delay);
-
- connection.interrupt();
- connection.semaphore.acquireUninterruptibly();
- verify(connection, times(2)).sendMessage(notification);
-
- queued.stop();
- }
-
- protected ApnsService newService(ApnsConnection connection, ApnsFeedbackConnection feedback) {
- ApnsService service = new ApnsServiceImpl(connection, null);
- ApnsService queued = new QueuedApnsService(service);
- queued.start();
- return queued;
- }
-}
diff --git a/src/test/java/com/notnoop/apns/internal/QueuedApnsServiceTest.java b/src/test/java/com/notnoop/apns/internal/QueuedApnsServiceTest.java
deleted file mode 100644
index 846a9a6f..00000000
--- a/src/test/java/com/notnoop/apns/internal/QueuedApnsServiceTest.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import static org.junit.Assert.*;
-
-import java.io.IOException;
-import java.util.concurrent.Semaphore;
-
-import org.junit.Test;
-import static org.mockito.Mockito.*;
-
-import com.notnoop.apns.ApnsNotification;
-import com.notnoop.apns.ApnsService;
-import com.notnoop.apns.EnhancedApnsNotification;
-import com.notnoop.exceptions.NetworkIOException;
-
-public class QueuedApnsServiceTest {
-
- @Test(expected = IllegalStateException.class)
- public void sendWithoutStarting() {
- QueuedApnsService service = new QueuedApnsService(null);
- service.push(notification);
- }
- EnhancedApnsNotification notification = new EnhancedApnsNotification(1,
- EnhancedApnsNotification.MAXIMUM_EXPIRY, "2342", "{}");
-
- @Test
- public void pushEventually() {
- ConnectionStub connection = spy(new ConnectionStub(0, 1));
- ApnsService service = newService(connection, null);
-
- service.push(notification);
- connection.semaphore.acquireUninterruptibly();
-
- verify(connection, times(1)).sendMessage(notification);
- }
-
- @Test
- public void pushEventuallySample() {
- ConnectionStub connection = spy(new ConnectionStub(0, 1));
- ApnsService service = newService(connection, null);
-
- service.push("2342", "{}");
- connection.semaphore.acquireUninterruptibly();
-
- verify(connection, times(1)).sendMessage(notification);
- }
-
- @Test
- public void doNotBlock() {
- final int delay = 10000;
- ConnectionStub connection = spy(new ConnectionStub(delay, 2));
- QueuedApnsService queued =
- new QueuedApnsService(new ApnsServiceImpl(connection, null));
- queued.start();
- long time1 = System.currentTimeMillis();
- queued.push(notification);
- queued.push(notification);
- long time2 = System.currentTimeMillis();
- assertTrue("queued.push() blocks", (time2 - time1) < delay);
-
- connection.interrupt();
- connection.semaphore.acquireUninterruptibly();
- verify(connection, times(2)).sendMessage(notification);
-
- queued.stop();
- }
-
- protected ApnsService newService(ApnsConnection connection, ApnsFeedbackConnection feedback) {
- ApnsService service = new ApnsServiceImpl(connection, null);
- ApnsService queued = new QueuedApnsService(service);
- queued.start();
- return queued;
- }
-
- static class ConnectionStub implements ApnsConnection {
-
- Semaphore semaphore;
- int delay;
-
- public ConnectionStub(int delay, int expectedCalls) {
- this.semaphore = new Semaphore(1 - expectedCalls);
- this.delay = delay;
- }
- volatile boolean stop;
-
- public synchronized void sendMessage(ApnsNotification m) {
- long time = System.currentTimeMillis();
- while (!stop && (System.currentTimeMillis() < time + delay)) {
- // WTF? Here was a busy wait for up to 10 seconds or until "stop" fired. Added: A tiny amount of sleep every round.
- try {
- Thread.sleep(2);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
- semaphore.release();
- }
-
- protected void interrupt() {
- stop = true;
- }
-
- public ApnsConnection copy() {
- throw new RuntimeException("Not implemented");
- }
-
- public void close() throws IOException {
- }
-
- public void testConnection() throws NetworkIOException {
- }
-
- public void setCacheLength(int cacheLength) {
- }
-
- public int getCacheLength() {
- return -1;
- }
- }
-}
diff --git a/src/test/java/com/notnoop/apns/internal/SillyTests.java b/src/test/java/com/notnoop/apns/internal/SillyTests.java
deleted file mode 100644
index f51da395..00000000
--- a/src/test/java/com/notnoop/apns/internal/SillyTests.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import java.util.Collections;
-import java.util.Date;
-import java.util.Map;
-
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.*;
-
-public class SillyTests {
-
- @Test
- public void testFeedbackCalls() {
- Map map = Collections.singletonMap("Test", new Date());
- ApnsFeedbackConnection feed = mock(ApnsFeedbackConnection.class);
- when(feed.getInactiveDevices()).thenReturn(map);
-
- ApnsServiceImpl service = new ApnsServiceImpl(null, feed);
- assertEquals(map, service.getInactiveDevices());
-
- // The feedback should be called once at most
- // Otherwise, we need to verify that the results of both
- // calls are accounted for
- verify(feed, times(1)).getInactiveDevices();
- }
-
- @Test
- public void testQueuedFeedbackCalls() {
- Map map = Collections.singletonMap("Test", new Date());
- ApnsFeedbackConnection feed = mock(ApnsFeedbackConnection.class);
- when(feed.getInactiveDevices()).thenReturn(map);
-
- ApnsServiceImpl service = new ApnsServiceImpl(null, feed);
- QueuedApnsService queued = new QueuedApnsService(service);
- assertEquals(map, queued.getInactiveDevices());
-
- // The feedback should be called once at most
- // Otherwise, we need to verify that the results of both
- // calls are accounted for
- verify(feed, times(1)).getInactiveDevices();
- }
-
-}
diff --git a/src/test/java/com/notnoop/apns/internal/SimpleApnsNotificationTest.java b/src/test/java/com/notnoop/apns/internal/SimpleApnsNotificationTest.java
deleted file mode 100644
index 29660941..00000000
--- a/src/test/java/com/notnoop/apns/internal/SimpleApnsNotificationTest.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import static org.junit.Assert.*;
-
-import org.junit.experimental.theories.*;
-import org.junit.runner.RunWith;
-
-import com.notnoop.apns.PayloadBuilder;
-import com.notnoop.apns.SimpleApnsNotification;
-import com.notnoop.apns.internal.Utilities;
-
-import static com.notnoop.apns.PayloadBuilder.*;
-import static com.notnoop.apns.internal.Utilities.*;
-
-@SuppressWarnings("deprecation")
-@RunWith(Theories.class)
-public class SimpleApnsNotificationTest {
-
- // Device Tokens
- @DataPoints public static String[] deviceTokens =
- {
- "298893742908AB98C",
- "98234098203BACCCC93284092"
- };
-
- // Messages
- @DataPoints public static PayloadBuilder[] payloaders =
- {
- newPayload().alertBody("test").sound("default"),
- newPayload().sound("chimes").actionKey("Cancel"),
- newPayload().customField("notice", "this")
- };
-
- @Theory
- public void lengthConsistency(String deviceToken, PayloadBuilder payload) {
- SimpleApnsNotification msg = new SimpleApnsNotification(deviceToken, payload.build());
- assertEquals(msg.marshall().length, msg.length());
- }
-
- @Theory
- public void commandIsZero(String deviceToken, PayloadBuilder payload) {
- SimpleApnsNotification msg = new SimpleApnsNotification(deviceToken, payload.build());
- byte[] bytes = msg.marshall();
- assertEquals(0, /*command part*/ bytes[0]);
- }
-
- @Theory
- public void deviceTokenPart(String deviceToken, PayloadBuilder payload) {
- SimpleApnsNotification msg = new SimpleApnsNotification(deviceToken, payload.build());
- byte[] bytes = msg.marshall();
-
- byte[] dt = decodeHex(deviceToken);
- assertEquals(dt.length, /* found length */ ((bytes[1] & 0xff) << 8) + (bytes[2]& 0xff));
-
- // verify the device token part
- assertArrayEquals(dt, Utilities.copyOfRange(bytes, 3, 3 + dt.length));
- }
-
- @Theory
- public void payloadPart(String deviceToken, PayloadBuilder payload) {
- String payloadString = payload.build();
- SimpleApnsNotification msg = new SimpleApnsNotification(deviceToken, payloadString);
- byte[] bytes = msg.marshall();
-
- byte[] pl = toUTF8Bytes(payloadString);
-
- // in reverse
- int plBegin = bytes.length - pl.length;
-
- /// verify the payload part
- assertArrayEquals(pl, Utilities.copyOfRange(bytes, plBegin, bytes.length));
- assertEquals(pl.length, ((bytes[plBegin - 2] & 0xff) << 8) + (bytes[plBegin - 1] & 0xff));
- }
-
- @Theory
- public void allPartsLength(String deviceToken, PayloadBuilder payload) {
- String payloadString = payload.build();
- SimpleApnsNotification msg = new SimpleApnsNotification(deviceToken, payloadString);
- byte[] bytes = msg.marshall();
-
- int expectedLength = 1
- + 2 + decodeHex(deviceToken).length
- + 2 + toUTF8Bytes(payloadString).length;
- assertEquals(expectedLength, bytes.length);
- }
-}
diff --git a/src/test/java/com/notnoop/apns/internal/TlsTunnelBuilderTest.java b/src/test/java/com/notnoop/apns/internal/TlsTunnelBuilderTest.java
deleted file mode 100644
index 833bed55..00000000
--- a/src/test/java/com/notnoop/apns/internal/TlsTunnelBuilderTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-//import java.net.InetSocketAddress;
-//import java.net.Proxy;
-//import java.net.Socket;
-import org.junit.Test;
-import static org.junit.Assert.fail;
-
-public class TlsTunnelBuilderTest {
-
- @Test
- public void makeTunnelSuccess() throws IOException {
- /* Uncomment this test to verify with your proxy settings */
- /*try {
- Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy.mydomain.com", 8080));
-
- InetSocketAddress proxyAddress = (InetSocketAddress) proxy.address();
- Socket proxySocket = new Socket(proxyAddress.getAddress(), proxyAddress.getPort());
- InetSocketAddress destAddress = new InetSocketAddress("myhost.com", 2195);
-
- new TlsTunnelBuilder().makeTunnel(destAddress.getAddress().toString(),
- destAddress.getPort(),
- "proxy-username", "proxy-password",
- proxyAddress);
- } catch (IOException ex){
- fail();
- }*/
-
- }
-
- @Test
- public void invalidProxyParams() throws IOException {
- try {
- new TlsTunnelBuilder().makeTunnel("origin.example.com", 9876, null, null, null);
- fail();
- } catch (IOException expected) {
- // No operation
- }
- }
-
- private InputStream inputStream(String content) throws IOException {
- return new ByteArrayInputStream(content.getBytes("UTF-8"));
- }
-}
diff --git a/src/test/java/com/notnoop/apns/internal/UtilitiesTest.java b/src/test/java/com/notnoop/apns/internal/UtilitiesTest.java
deleted file mode 100644
index 251dc139..00000000
--- a/src/test/java/com/notnoop/apns/internal/UtilitiesTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.internal;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-public class UtilitiesTest {
-
- @Test
- public void testEncodeAndDecode() {
- String encodedHex = "a1b2d4";
-
- byte[] decoded = Utilities.decodeHex(encodedHex);
- String encoded = Utilities.encodeHex(decoded);
-
- Assert.assertEquals(encodedHex.toLowerCase(), encoded.toLowerCase());
- }
-
- @Test
- public void testParsingBytes() {
- Assert.assertEquals(0xFF00FF00, Utilities.parseBytes(0xFF, 0, 0xFF, 0));
- Assert.assertEquals(0x00FF00FF, Utilities.parseBytes(0, 0xFF, 0, 0xFF));
- Assert.assertEquals(0xDEADBEEF, Utilities.parseBytes(0xDE, 0xAD, 0xBE, 0xEF));
- Assert.assertEquals(0x0EADBEEF, Utilities.parseBytes(0x0E, 0xAD, 0xBE, 0xEF));
-
- Assert.assertTrue(Utilities.parseBytes(0xF0, 0,0,0) < 0);
- Assert.assertTrue(Utilities.parseBytes(0x80, 0,0,0) < 0);
- Assert.assertTrue(Utilities.parseBytes(0x70, 0,0,0) > 0);
- }
-
- @Test
- public void testEncodingUTF8() {
- String m = "esemény";
-
- // See http://en.wikipedia.org/wiki/Unicode_equivalence#Example
- //
- // Oh the joy as different platforms choose to normalize Unicode differently ... but both are valid.
- //
- // This is intended to fix a problem under jdk 6, I was not able to reproduce it with jdk 7u51 on OSX Mavericks
- // (Java seems to also use expected_NFC here).
- byte[] expected_NFC = {
- 'e', 's', 'e', 'm', (byte)0x00C3, (byte)0x00A9, 'n', 'y'
- };
-
- byte[] expected_NFD = {
- 'e', 's', 'e', 'm', (byte)0x00cc, (byte)0x0081, (byte)0x0061, 'n', 'y'
- };
-
- final byte[] bytes = Utilities.toUTF8Bytes(m);
-
- if (bytes.length == 8) {
- Assert.assertArrayEquals(expected_NFC, bytes);
- } else {
- Assert.assertArrayEquals(expected_NFD, bytes);
- }
-
- }
-}
diff --git a/src/test/java/com/notnoop/apns/utils/ApnsServerStub.java b/src/test/java/com/notnoop/apns/utils/ApnsServerStub.java
deleted file mode 100644
index 95d24f38..00000000
--- a/src/test/java/com/notnoop/apns/utils/ApnsServerStub.java
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.utils;
-
-import javax.net.ServerSocketFactory;
-import javax.net.ssl.SSLServerSocket;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.Socket;
-import java.net.SocketException;
-import java.nio.ByteBuffer;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.atomic.AtomicInteger;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class ApnsServerStub {
-
- /**
- * Create an ApnsServerStub
- *
- * @param gatePort port for the gateway stub server
- * @param feedPort port for the feedback stub server
- * @return an ApnsServerStub
- * @deprecated use prepareAndStartServer() without port numbers and query the port numbers from the server using
- * ApnsServerStub.getEffectiveGatewayPort() and ApnsServerStub.getEffectiveFeedbackPort()
- */
- @Deprecated
- public static ApnsServerStub prepareAndStartServer(int gatePort, int feedPort) {
- ApnsServerStub server = new ApnsServerStub(FixedCertificates.serverContext().getServerSocketFactory(), gatePort, feedPort);
- server.start();
- return server;
- }
-
- /**
- * Create an ApnsServerStub that uses any free port for gateway and feedback.
- *
- * @return the server stub. Use getEffectiveGatewayPort() and getEffectiveFeedbackPort() to ask for ports.
- */
- public static ApnsServerStub prepareAndStartServer() {
- ApnsServerStub server = new ApnsServerStub(FixedCertificates.serverContext().getServerSocketFactory());
- server.start();
- return server;
- }
-
- private static final Logger LOGGER = LoggerFactory.getLogger(ApnsServerStub.class);
- private final AtomicInteger toWaitBeforeSend = new AtomicInteger(0);
- private final ByteArrayOutputStream received;
- private final ByteArrayOutputStream toSend;
- private final Semaphore messages = new Semaphore(0);
- private final Semaphore startUp = new Semaphore(0);
- private final Semaphore gatewayOutLock = new Semaphore(0);
- private final Semaphore waitForError = new Semaphore(1);
- private final ServerSocketFactory sslFactory;
- private final int gatewayPort;
- private final int feedbackPort;
- private int effectiveGatewayPort;
- private int effectiveFeedbackPort;
- private OutputStream gatewayOutputStream;
-
- public ApnsServerStub(ServerSocketFactory sslFactory) {
- this(sslFactory, 0, 0);
- }
-
- public ApnsServerStub(ServerSocketFactory sslFactory, int gatewayPort, int feedbackPort) {
- this.sslFactory = sslFactory;
- this.gatewayPort = gatewayPort;
- this.feedbackPort = feedbackPort;
-
- this.received = new ByteArrayOutputStream();
- this.toSend = new ByteArrayOutputStream();
- }
-
- Thread gatewayThread;
- Thread feedbackThread;
- SSLServerSocket gatewaySocket;
- SSLServerSocket feedbackSocket;
-
- public void start() {
- gatewayThread = new GatewayRunner();
- feedbackThread = new FeedbackRunner();
- gatewayThread.start();
- feedbackThread.start();
- startUp.acquireUninterruptibly(2);
- }
-
- @SuppressWarnings("deprecation")
- public void stop() {
- try {
- if (gatewaySocket != null) {
- gatewaySocket.close();
- }
- } catch (IOException e) {
- LOGGER.warn("Can not close gatewaySocket properly", e);
- }
- try {
- if (feedbackSocket != null) {
- feedbackSocket.close();
- }
- } catch (IOException e) {
- LOGGER.warn("Can not close feedbackSocket properly", e);
- }
-
- if (gatewayThread != null) {
- gatewayThread.stop();
- }
-
- if (feedbackThread != null) {
- feedbackThread.stop();
- }
-
- }
-
- public void sendError(int err, int id) {
- ByteBuffer buf = ByteBuffer.allocate(6);
- buf.put((byte) 8).put((byte) err).putInt(id);
- try {
- gatewayOutLock.acquire();
- gatewayOutputStream.write(buf.array());
- gatewayOutputStream.flush();
- } catch (Exception ex) {
- LOGGER.warn("An error occured with accessing gateway", ex);
- }
- }
-
- public int getEffectiveGatewayPort() {
- return effectiveGatewayPort;
- }
-
- public int getEffectiveFeedbackPort() {
- return effectiveFeedbackPort;
- }
-
- public AtomicInteger getToWaitBeforeSend() {
- return toWaitBeforeSend;
- }
-
- public ByteArrayOutputStream getReceived() {
- return received;
- }
-
- public ByteArrayOutputStream getToSend() {
- return toSend;
- }
-
- public Semaphore getMessages() {
- return messages;
- }
-
- public Semaphore getWaitForError() {
- return waitForError;
- }
-
- private class GatewayRunner extends Thread {
-
- @SuppressWarnings("InfiniteLoopStatement")
- public void run() {
- Thread.currentThread().setName("GatewayThread");
- try {
- gatewaySocket = (SSLServerSocket)sslFactory.createServerSocket(gatewayPort);
- gatewaySocket.setNeedClientAuth(true);
- } catch (IOException e) {
- messages.release();
- throw new RuntimeException(e);
- }
-
- InputStream in = null;
- effectiveGatewayPort = gatewaySocket.getLocalPort();
-
- try {
- // Listen for connections
- startUp.release();
- while (true) {
- Socket socket = gatewaySocket.accept();
- // Work around JVM deadlock ... https://community.oracle.com/message/10989561#10989561
- socket.setSoLinger(true, 1);
-
- // Create streams to securely send and receive data to the client
- in = socket.getInputStream();
- gatewayOutputStream = socket.getOutputStream();
- gatewayOutLock.release();
-
- // Read from in and write to out...
- byte[] read = readFully(in);
-
- waitBeforeSend();
- received.write(read);
- messages.release();
-
-
- waitForError.acquire();
-
- // Close the socket
- in.close();
- gatewayOutputStream.close();
- }
- } catch (Throwable e) {
- try {
- if (in != null) {
- in.close();
- }
- } catch (IOException ioex) {
- LOGGER.warn("Can not close socket properly", ioex);
- }
- try {
- if (gatewayOutputStream != null) {
- gatewayOutputStream.close();
- }
- } catch (IOException ioex) {
- LOGGER.warn("Can not close gatewayOutputStream properly", ioex);
- }
- messages.release();
- }
- }
-
- }
-
- private class FeedbackRunner extends Thread {
-
- public void run() {
- Thread.currentThread().setName("FeedbackThread");
- try {
- feedbackSocket = (SSLServerSocket)sslFactory.createServerSocket(feedbackPort);
- feedbackSocket.setNeedClientAuth(true);
- } catch (IOException e) {
- e.printStackTrace();
- messages.release();
- throw new RuntimeException(e);
- }
-
- effectiveFeedbackPort = feedbackSocket.getLocalPort();
- try {
- // Listen for connections
- startUp.release();
- Socket socket = feedbackSocket.accept();
- // Work around JVM deadlock ... https://community.oracle.com/message/10989561#10989561
- socket.setSoLinger(true, 1);
-
- // Create streams to securely send and receive data to the client
- InputStream in = socket.getInputStream();
- OutputStream out = socket.getOutputStream();
-
- waitBeforeSend();
- // Read from in and write to out...
- toSend.writeTo(out);
-
- // Close the socket
- in.close();
- out.close();
- } catch (SocketException se) {
- // Ignore closed socket.
- } catch (IOException ioex) {
- ioex.printStackTrace();
- }
- messages.release();
- }
- }
-
- AtomicInteger readLen = new AtomicInteger();
-
- public void stopAt(int length) {
- readLen.set(length);
- }
-
- public byte[] readFully(InputStream st) {
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
-
- int read;
- try {
- while (readLen.getAndDecrement() > 0 && (read = st.read()) != -1) {
- stream.write(read);
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
-
-
- return stream.toByteArray();
- }
-
- /**
- * Introduces a waiting time, used to trigger read timeouts.
- */
- private void waitBeforeSend() {
- int wait = toWaitBeforeSend.get();
- if (wait != 0) {
- try {
- Thread.sleep(wait);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
- }
-
-}
diff --git a/src/test/java/com/notnoop/apns/utils/FixedCertificates.java b/src/test/java/com/notnoop/apns/utils/FixedCertificates.java
deleted file mode 100644
index d9f69d33..00000000
--- a/src/test/java/com/notnoop/apns/utils/FixedCertificates.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.utils;
-
-import com.notnoop.apns.internal.SSLContextBuilder;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.X509TrustManager;
-import java.io.InputStream;
-
-public class FixedCertificates {
-
- public static final String CLIENT_STORE = "clientStore.p12";
- public static final String CLIENT_PASSWORD = "123456";
-
- public static final String CLIENT_MULTI_KEY_STORE = "clientStore.jks";
- public static final String CLIENT_MULTI_KEY_PASSWORD = "123456";
-
- public static final String SERVER_STORE = "serverStore.p12";
- public static final String SERVER_PASSWORD = "123456";
-
- public static final String SERVER_TRUST_STORE = "serverTrustStore.p12";
- public static final String SERVER_TRUST_PASSWORD = "123456";
-
- public static final String LOCALHOST = "localhost";
-
- public static SSLContext serverContext() {
- try {
- InputStream stream = FixedCertificates.class.getResourceAsStream("/" + SERVER_STORE);
- InputStream trustStream = FixedCertificates.class.getResourceAsStream("/" + SERVER_TRUST_STORE);
- assert stream != null;
- return new SSLContextBuilder()
- .withAlgorithm("sunx509")
- .withCertificateKeyStore(stream, SERVER_PASSWORD, "PKCS12")
- .withTrustKeyStore(trustStream, SERVER_TRUST_PASSWORD, "PKCS12")
- .build();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- public static SSLContext clientContext() {
- try {
- InputStream stream = FixedCertificates.class.getResourceAsStream("/" + CLIENT_STORE);
- assert stream != null;
- return new SSLContextBuilder()
- .withAlgorithm("sunx509")
- .withCertificateKeyStore(stream, CLIENT_PASSWORD, "PKCS12")
- .withTrustManager(new X509TrustManagerTrustAll())
- .build();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- public static SSLContext clientMultiKeyContext(String keyAlias) {
- try {
- InputStream stream = FixedCertificates.class.getResourceAsStream("/" + CLIENT_MULTI_KEY_STORE);
- assert stream != null;
- return new SSLContextBuilder()
- .withAlgorithm("sunx509")
- .withCertificateKeyStore(stream, CLIENT_MULTI_KEY_PASSWORD, "JKS", keyAlias)
- .withTrustManager(new X509TrustManagerTrustAll())
- .build();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- public static String clientCertPath() {
- return ClassLoader.getSystemResource(CLIENT_STORE).getPath();
- }
-
- static class X509TrustManagerTrustAll implements X509TrustManager {
- public boolean checkClientTrusted(java.security.cert.X509Certificate[] chain){
- return true;
- }
-
- public boolean isServerTrusted(java.security.cert.X509Certificate[] chain){
- return true;
- }
-
- public boolean isClientTrusted(java.security.cert.X509Certificate[] chain){
- return true;
- }
-
- public java.security.cert.X509Certificate[] getAcceptedIssuers() {
- return null;
- }
-
- public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {}
-
- public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {}
- }
-
-}
diff --git a/src/test/java/com/notnoop/apns/utils/Simulator/Action.java b/src/test/java/com/notnoop/apns/utils/Simulator/Action.java
deleted file mode 100644
index fdaddb6e..00000000
--- a/src/test/java/com/notnoop/apns/utils/Simulator/Action.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.utils.Simulator;
-
-public enum Action {
- DO_NOTHING, RETURN_ERROR, RETURN_ERROR_AND_SHUTDOWN
-}
diff --git a/src/test/java/com/notnoop/apns/utils/Simulator/ApnsInputStream.java b/src/test/java/com/notnoop/apns/utils/Simulator/ApnsInputStream.java
deleted file mode 100644
index 189ca3a4..00000000
--- a/src/test/java/com/notnoop/apns/utils/Simulator/ApnsInputStream.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.utils.Simulator;
-
-import java.io.ByteArrayInputStream;
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.ByteBuffer;
-
-public class ApnsInputStream extends DataInputStream {
- public ApnsInputStream(final InputStream inputStream) {
- super(inputStream);
- }
-
- byte[] readBlob() throws IOException {
- int length = readUnsignedShort();
- byte[] blob = new byte[length];
- readFully(blob);
- return blob;
- }
-
- ApnsInputStream readFrame() throws IOException {
- int length = readInt();
- byte[] buffer = new byte[length];
- readFully(buffer);
- final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(buffer);
- return new ApnsInputStream(byteArrayInputStream);
- }
-
- public Item readItem() throws IOException {
- byte itemId = readByte();
- byte[] blob = readBlob();
- return new Item(itemId, blob);
- }
-
- public static class Item {
- public final static byte ID_DEVICE_TOKEN = 1;
- public final static byte ID_PAYLOAD = 2;
- public final static byte ID_NOTIFICATION_IDENTIFIER = 3;
- public final static byte ID_EXPIRATION_DATE = 4;
- public final static byte ID_PRIORITY = 5;
- public final static Item DEFAULT = new Item((byte)0, new byte[0]);
-
- private final byte itemId;
- private final byte[] blob;
-
- public Item(final byte itemId, final byte[] blob) {
-
- this.itemId = itemId;
- this.blob = blob;
- }
-
- public byte getItemId() {
- return itemId;
- }
-
- public byte[] getBlob() {
- return blob.clone();
- }
-
- public int getInt() { return blob.length < 4 ? 0 : ByteBuffer.wrap(blob).getInt(); }
-
- public byte getByte() { return blob.length < 1 ? 0 : blob[0]; }
- }
-}
diff --git a/src/test/java/com/notnoop/apns/utils/Simulator/ApnsNotificationWithAction.java b/src/test/java/com/notnoop/apns/utils/Simulator/ApnsNotificationWithAction.java
deleted file mode 100644
index b05bc6ef..00000000
--- a/src/test/java/com/notnoop/apns/utils/Simulator/ApnsNotificationWithAction.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.utils.Simulator;
-
-import com.notnoop.apns.utils.Simulator.ApnsServerSimulator.Notification;
-
-public class ApnsNotificationWithAction {
- private final Notification notification;
- private final ApnsResponse response;
-
- public ApnsNotificationWithAction(Notification notification) {
- this(notification, ApnsResponse.doNothing());
- }
-
- public ApnsNotificationWithAction(Notification notification, ApnsResponse response) {
- if (notification == null)
- {
- throw new NullPointerException("notification cannot be null");
- }
- this.notification = notification;
- if (response == null)
- {
- throw new NullPointerException("response cannot be null");
- }
- this.response = response;
- }
-
- public Notification getNotification() {
- return notification;
- }
-
- public int getId() {
- return notification.getIdentifier();
- }
-
- public ApnsResponse getResponse() {
- return response;
- }
-
-}
diff --git a/src/test/java/com/notnoop/apns/utils/Simulator/ApnsResponse.java b/src/test/java/com/notnoop/apns/utils/Simulator/ApnsResponse.java
deleted file mode 100644
index 8fcc7d9d..00000000
--- a/src/test/java/com/notnoop/apns/utils/Simulator/ApnsResponse.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.utils.Simulator;
-
-import com.notnoop.apns.ApnsNotification;
-import com.notnoop.apns.DeliveryError;
-
-public class ApnsResponse {
-
- private final Action action;
- private final DeliveryError error;
- private final int errorId;
-
- private ApnsResponse(Action action, DeliveryError error, int errorId) {
- this.action = action;
- this.error = error;
- this.errorId = errorId;
- }
-
- public boolean isDoNothing() {
- return action == Action.DO_NOTHING;
- }
-
- public Action getAction() {
- return action;
- }
-
- public DeliveryError getError() {
- return error;
- }
-
- public int getErrorId() {
- return errorId;
- }
-
- public static ApnsResponse doNothing() {
- return new ApnsResponse(Action.DO_NOTHING, null, 0);
- }
-
- public static ApnsResponse returnError(DeliveryError error, int errorId) {
- return new ApnsResponse(Action.RETURN_ERROR, error, errorId);
- }
-
- public static ApnsResponse returnErrorAndShutdown(DeliveryError error, int errorId) {
- return new ApnsResponse(Action.RETURN_ERROR_AND_SHUTDOWN, error, errorId);
- }
-
- public static ApnsResponse returnErrorAndShutdown(DeliveryError error, ApnsNotification notification) {
- return new ApnsResponse(Action.RETURN_ERROR_AND_SHUTDOWN, error, notification.getIdentifier());
- }
-
-}
diff --git a/src/test/java/com/notnoop/apns/utils/Simulator/ApnsServerSimulator.java b/src/test/java/com/notnoop/apns/utils/Simulator/ApnsServerSimulator.java
deleted file mode 100644
index 0e93068c..00000000
--- a/src/test/java/com/notnoop/apns/utils/Simulator/ApnsServerSimulator.java
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.utils.Simulator;
-
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
-import java.io.EOFException;
-import java.io.IOException;
-import java.net.ServerSocket;
-import java.net.SocketException;
-import java.nio.*;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.atomic.AtomicInteger;
-import javax.net.ServerSocketFactory;
-import com.notnoop.apns.internal.Utilities;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public abstract class ApnsServerSimulator {
-
- private static final Logger logger = LoggerFactory.getLogger(ApnsServerSimulator.class);
- private static AtomicInteger threadNameCount = new AtomicInteger(0);
-
- private final Semaphore startUp = new Semaphore(0);
- private final ServerSocketFactory sslFactory;
-
- private int effectiveGatewayPort;
- private int effectiveFeedbackPort;
-
- public ApnsServerSimulator(ServerSocketFactory sslFactory) {
- this.sslFactory = sslFactory;
- }
-
- Thread gatewayThread;
- Thread feedbackThread;
- ServerSocket gatewaySocket;
- ServerSocket feedbackSocket;
-
- public void start() {
- logger.debug("Starting APNSServerSimulator");
- gatewayThread = new GatewayListener();
- feedbackThread = new FeedbackRunner();
- gatewayThread.start();
- feedbackThread.start();
- startUp.acquireUninterruptibly(2);
- }
-
- public void stop() {
- logger.debug("Stopping APNSServerSimulator");
- try {
- if (gatewaySocket != null) {
- gatewaySocket.close();
- }
- } catch (IOException e) {
- logger.warn("Can not close gatewaySocket properly", e);
- }
- try {
- if (feedbackSocket != null) {
- feedbackSocket.close();
- }
- } catch (IOException e) {
- logger.warn("Can not close feedbackSocket properly", e);
- }
-
- if (gatewayThread != null) {
- gatewayThread.interrupt();
- }
-
- if (feedbackThread != null) {
- feedbackThread.interrupt();
- }
- logger.debug("Stopped - APNSServerSimulator");
-
- }
-
- public int getEffectiveGatewayPort() {
- return effectiveGatewayPort;
- }
-
- public int getEffectiveFeedbackPort() {
- return effectiveFeedbackPort;
- }
-
- private class GatewayListener extends Thread {
-
- private GatewayListener() {
- super(new ThreadGroup("GatewayListener" + threadNameCount.incrementAndGet()), "");
- setName(getThreadGroup().getName());
- }
-
- public void run() {
- logger.debug("Launched " + Thread.currentThread().getName());
- try {
-
- try {
- gatewaySocket = sslFactory.createServerSocket(0);
- } catch (IOException e) {
- e.printStackTrace();
- throw new RuntimeException(e);
- }
-
- effectiveGatewayPort = gatewaySocket.getLocalPort();
-
- // Listen for connections
- startUp.release();
-
- while (!isInterrupted()) {
- try {
- handleGatewayConnection(new InputOutputSocket(gatewaySocket.accept()));
- } catch (SocketException ex) {
- logger.warn("Interruption while handling gateway connection", ex);
- interrupt();
- } catch (IOException ioe) {
- logger.warn("An error occured while handling gateway connection", ioe);
- }
- }
- } finally {
- logger.debug("Terminating " + Thread.currentThread().getName());
- getThreadGroup().list();
- getThreadGroup().interrupt();
- }
- }
-
- private void handleGatewayConnection(final InputOutputSocket inputOutputSocket) throws IOException {
- Thread gatewayConnectionTread = new Thread() {
- @Override
- public void run() {
- try {
- parseNotifications(inputOutputSocket);
- } finally {
- inputOutputSocket.close();
- }
- }
- };
- gatewayConnectionTread.start();
- }
-
- private void parseNotifications(final InputOutputSocket inputOutputSocket) {
- logger.debug("Running parseNotifications {}", inputOutputSocket.getSocket());
- while (!Thread.interrupted()) {
- try {
- final ApnsInputStream inputStream = inputOutputSocket.getInputStream();
- byte notificationType = inputStream.readByte();
- logger.debug("Received Notification (type {})", notificationType);
- switch (notificationType) {
- case 0:
- readLegacyNotification(inputOutputSocket);
- break;
- case 1:
- readEnhancedNotification(inputOutputSocket);
- break;
- case 2:
- readFramedNotifications(inputOutputSocket);
- break;
- }
- } catch (IOException ioe) {
- logger.warn("An error occured while reading notification", ioe);
- Thread.currentThread().interrupt();
- }
- }
- }
-
- private void readFramedNotifications(final InputOutputSocket inputOutputSocket) throws IOException {
-
- Map map = new HashMap();
-
- ApnsInputStream frameStream = inputOutputSocket.getInputStream().readFrame();
- try {
- while (!Thread.currentThread().isInterrupted()) {
- final ApnsInputStream.Item item = frameStream.readItem();
- map.put(item.getItemId(), item);
- }
- } catch (EOFException eof) {
- // Done reading.
- }
-
- byte[] deviceToken = get(map, ApnsInputStream.Item.ID_DEVICE_TOKEN).getBlob();
- byte[] payload = get(map, ApnsInputStream.Item.ID_PAYLOAD).getBlob();
- int identifier = get(map, ApnsInputStream.Item.ID_NOTIFICATION_IDENTIFIER).getInt();
- int expiry = get(map, ApnsInputStream.Item.ID_EXPIRATION_DATE).getInt();
- byte priority = get(map, ApnsInputStream.Item.ID_PRIORITY).getByte();
-
- final Notification notification = new Notification(2, identifier, expiry, deviceToken, payload, priority);
- logger.debug("Read framed notification {}", notification);
- onNotification(notification, inputOutputSocket);
-
- }
-
- private ApnsInputStream.Item get(final Map map, final byte idDeviceToken) {
- ApnsInputStream.Item item = map.get(idDeviceToken);
- if (item == null) {
- item = ApnsInputStream.Item.DEFAULT;
- }
- return item;
- }
-
- private void readEnhancedNotification(final InputOutputSocket inputOutputSocket) throws IOException {
- ApnsInputStream inputStream = inputOutputSocket.getInputStream();
-
- int identifier = inputStream.readInt();
- int expiry = inputStream.readInt();
- final byte[] deviceToken = inputStream.readBlob();
- final byte[] payload = inputStream.readBlob();
- final Notification notification = new Notification(1, identifier, expiry, deviceToken, payload);
- logger.debug("Read enhanced notification {}", notification);
- onNotification(notification, inputOutputSocket);
- }
-
- private void readLegacyNotification(final InputOutputSocket inputOutputSocket) throws IOException {
- ApnsInputStream inputStream = inputOutputSocket.getInputStream();
-
- final byte[] deviceToken = inputStream.readBlob();
- final byte[] payload = inputStream.readBlob();
- final Notification notification = new Notification(0, deviceToken, payload);
- logger.debug("Read legacy notification {}", notification);
- onNotification(notification, inputOutputSocket);
-
- }
-
- @Override
- public void interrupt() {
- logger.debug("Interrupt, closing socket");
- super.interrupt();
- try {
- gatewaySocket.close();
- } catch (IOException e) {
- logger.warn("Can not close gatewaySocket properly", e);
- }
- }
- }
-
- protected void fail(final byte status, final int identifier, final InputOutputSocket inputOutputSocket) throws IOException {
- logger.debug("FAIL {} {}", status, identifier);
-
- // Here comes the fun ... we need to write the feedback packet as one single packet
- // or the client will notice the connection to be closed before it read the complete packet.
- // But - only on linux, however. (I was not able to see that problem on Windows 7 or OS X)
- // What also helped was inserting a little sleep between the flush and closing the connection.
- //
- // I believe this is irregular (writing to a tcp socket then closing it should result in ALL data
- // being visible at the client) but interestingly in Netty there is (was) a similar problem:
- // https://github.com/netty/netty/issues/1952
- //
- // Funnily that appeared as somebody ported this library to use netty.
- //
- //
- //
- ByteBuffer bb = ByteBuffer.allocate(6);
- bb.put((byte) 8);
- bb.put(status);
- bb.putInt(identifier);
- inputOutputSocket.syncWrite(bb.array());
- inputOutputSocket.close();
- logger.debug("FAIL - closed");
- }
-
- private class FeedbackRunner extends Thread {
-
- private FeedbackRunner() {
- super(new ThreadGroup("FeedbackRunner" + threadNameCount.incrementAndGet()), "");
- setName(getThreadGroup().getName());
- }
-
- public void run() {
- try {
- logger.debug("Launched " + Thread.currentThread().getName());
- try {
- feedbackSocket = sslFactory.createServerSocket(0);
- } catch (IOException e) {
- e.printStackTrace();
- throw new RuntimeException(e);
- }
-
- effectiveFeedbackPort = feedbackSocket.getLocalPort();
-
- startUp.release();
-
- while (!isInterrupted()) {
- try {
- handleFeedbackConnection(new InputOutputSocket(feedbackSocket.accept()));
- } catch (SocketException ex) {
- logger.warn("Interruption while handling feedback connection", ex);
- interrupt();
- } catch (IOException ioe) {
- logger.warn("An error occured while handling feedback connection", ioe);
- }
- }
- } finally {
- logger.debug("Terminating " + Thread.currentThread().getName());
- getThreadGroup().list();
- getThreadGroup().interrupt();
- }
- }
-
- private void handleFeedbackConnection(final InputOutputSocket inputOutputSocket) {
- Thread feedbackConnectionTread = new Thread() {
- @Override
- public void run() {
- try {
- logger.debug("Feedback connection sending feedback");
- sendFeedback(inputOutputSocket);
- } catch (IOException ioe) {
- // An exception is unexpected here. Close the current connection and bail out.
- logger.warn("An error occured while sending feedback", ioe);
- } finally {
- inputOutputSocket.close();
- }
-
- }
- };
- feedbackConnectionTread.start();
- }
-
- private void sendFeedback(final InputOutputSocket inputOutputSocket) throws IOException {
- List badTokens = getBadTokens();
-
- for (byte[] token : badTokens) {
- writeFeedback(inputOutputSocket, token);
- }
- }
-
- private void writeFeedback(final InputOutputSocket inputOutputSocket, final byte[] token) throws IOException {
- ByteArrayOutputStream os = new ByteArrayOutputStream();
- DataOutputStream dos = new DataOutputStream(os);
- final int unixTime = (int) (new Date().getTime() / 1000);
- dos.writeInt(unixTime);
- dos.writeShort((short) token.length);
- dos.write(token);
- dos.close();
- inputOutputSocket.syncWrite(os.toByteArray());
- }
- }
-
-
- @SuppressWarnings("UnusedDeclaration")
- public class Notification {
- private final int type;
- private final int identifier;
- private final int expiry;
- private final byte[] deviceToken;
- private final byte[] payload;
- private final byte priority;
-
- public Notification(final int type, final byte[] deviceToken, final byte[] payload) {
- this(type, 0, 0, deviceToken, payload);
- }
-
- public Notification(final int type, final int identifier, final int expiry, final byte[] deviceToken, final byte[] payload) {
- this(type, identifier, expiry, deviceToken, payload, (byte) 10);
-
- }
-
- public Notification(final int type, final int identifier, final int expiry, final byte[] deviceToken, final byte[] payload,
- final byte priority) {
- this.priority = priority;
- this.type = type;
- this.identifier = identifier;
- this.expiry = expiry;
- this.deviceToken = deviceToken;
- this.payload = payload;
- }
-
- public byte[] getPayload() {
- return payload.clone();
- }
-
- public byte[] getDeviceToken() {
- return deviceToken.clone();
- }
-
- public int getType() {
- return type;
- }
-
- public int getExpiry() {
- return expiry;
- }
-
- public int getIdentifier() {
- return identifier;
- }
-
- public byte getPriority() {
- return priority;
- }
-
- @Override
- public String toString() {
- return "Notification{" +
- "type=" + type +
- ", identifier=" + identifier +
- ", expiry=" + expiry +
- ", deviceToken=" + Utilities.encodeHex(deviceToken) +
- //", payload=" + Utilities.encodeHex(payload) +
- ", priority=" + priority +
- '}';
- }
- }
-
- protected void onNotification(final Notification notification, final InputOutputSocket inputOutputSocket) throws IOException {
- }
-
-
- protected List getBadTokens() {
- return new ArrayList();
- }
-}
diff --git a/src/test/java/com/notnoop/apns/utils/Simulator/ApnsSimulatorWithVerification.java b/src/test/java/com/notnoop/apns/utils/Simulator/ApnsSimulatorWithVerification.java
deleted file mode 100644
index b5e591bc..00000000
--- a/src/test/java/com/notnoop/apns/utils/Simulator/ApnsSimulatorWithVerification.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.utils.Simulator;
-
-import com.google.common.base.Strings;
-import com.notnoop.apns.EnhancedApnsNotification;
-import com.notnoop.apns.internal.Utilities;
-
-import javax.net.ServerSocketFactory;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Provides a simulator that receives connection over TCP as per a real APNS server. This class allows verification
- * and prior configuration of responses in a manner similar to a mocking framework.
- */
-public class ApnsSimulatorWithVerification extends ApnsServerSimulator {
-
- private List receivedNotifications;
- private Queue expectedWithResponses;
- private List unexpected;
-
- public ApnsSimulatorWithVerification(ServerSocketFactory sslFactory) {
- super(sslFactory);
- receivedNotifications = new ArrayList();
- expectedWithResponses = new ConcurrentLinkedQueue();
- unexpected = new ArrayList();
- }
-
- public void reset() {
- receivedNotifications.clear();
- expectedWithResponses.clear();
- unexpected.clear();
- }
-
- public List getReceivedNotifications() {
- return Collections.unmodifiableList(receivedNotifications);
- }
-
- private void addExpected(ApnsNotificationWithAction notificationWithAction) {
- expectedWithResponses.add(notificationWithAction);
- }
-
- protected void onNotification(final Notification notification, final InputOutputSocket inOutSocket)
- throws IOException {
- receivedNotifications.add(notification);
- pollExpectedResponses(notification, inOutSocket);
- }
-
- protected void pollExpectedResponses(Notification notification, InputOutputSocket inOutSocket) throws IOException {
- final ApnsNotificationWithAction withAction = expectedWithResponses.poll();
- if (withAction == null) {
- unexpected.add(notification);
- } else if (!matchNotificationWithExpected(withAction, notification)) {
- unexpected.add(notification);
- } else {
- handleNotificationWithAction(withAction, inOutSocket);
- }
- }
-
- protected void handleNotificationWithAction(ApnsNotificationWithAction notificationWithAction,
- InputOutputSocket inOutSocket) throws IOException {
- final ApnsResponse response = notificationWithAction.getResponse();
- if (!response.isDoNothing()) {
- if (response.getAction() == Action.RETURN_ERROR_AND_SHUTDOWN) {
- // have to stop first before sending out the error
- stop();
- sendError(response, inOutSocket);
- } else {
- sendError(response, inOutSocket);
- }
- }
- }
-
- private boolean matchNotificationWithExpected(ApnsNotificationWithAction withAction, Notification found) {
- if (withAction.getId() != found.getIdentifier()) {
- return false;
- }
- return matchDeviceToken(withAction.getNotification().getDeviceToken(), found.getDeviceToken());
- }
-
- private boolean matchDeviceToken(byte[] expected, byte[] found) {
- return Arrays.equals(expected, found);
- }
-
- protected void sendError(ApnsResponse response, InputOutputSocket inOutSocket) throws IOException {
- final byte status = (byte) response.getError().code();
- fail(status, response.getErrorId(), inOutSocket);
- }
-
- public DoResponse when(Notification notification) {
- return new DoResponse(notification);
- }
-
- public DoResponse when(EnhancedApnsNotification notification) {
- return new DoResponse(buildNotification(notification));
- }
-
- public void verify() {
- final int size = expectedWithResponses.size();
- if (size > 0) {
- final String error = String.format("[%d] Expected notification(s) were not received, first id was: [%d] ",
- size, expectedWithResponses.poll().getId());
- throw new IllegalStateException(error);
- }
- verifyUnexpected();
- }
-
- public void verifyAndWait(int waitSecs) {
- verifyUnexpected();
-
- long timeRemaining = TimeUnit.SECONDS.toMillis(waitSecs);
- final long sleepForMs = 250;
- while (!expectedWithResponses.isEmpty() && timeRemaining > 0) {
- sleep(sleepForMs < timeRemaining ? sleepForMs : timeRemaining);
- timeRemaining -= sleepForMs;
- }
- verify();
- }
-
- private void verifyUnexpected() {
- if (!unexpected.isEmpty()) {
- final Notification firstUnexpected = this.unexpected.get(0);
- throw new IllegalStateException(String.format("Unexpected notifications received, count: [%d]. First" +
- " notification is for id: [%d], deviceToken: [%s]", unexpected.size(),
- firstUnexpected.getIdentifier(), Utilities.encodeHex(firstUnexpected.getDeviceToken())));
- }
- }
-
- private void sleep(long ms) {
- try {
- Thread.sleep(ms);
- } catch (InterruptedException ex) {
- throw new RuntimeException(ex);
- }
- }
-
- public Notification buildNotification(EnhancedApnsNotification notification) {
- return new Notification(1, notification.getIdentifier(), notification.getExpiry(),
- notification.getDeviceToken(), notification.getPayload());
- }
-
- public class DoResponse {
- private final Notification expected;
-
- public DoResponse(Notification notification) {
- this.expected = notification;
- }
-
- public ApnsSimulatorWithVerification thenRespond(ApnsResponse response) {
- addExpected(new ApnsNotificationWithAction(expected, response));
- return ApnsSimulatorWithVerification.this;
- }
-
- public ApnsSimulatorWithVerification thenDoNothing() {
- addExpected(new ApnsNotificationWithAction(expected, ApnsResponse.doNothing()));
- return ApnsSimulatorWithVerification.this;
- }
- }
-
- public static String deviceTokenForId(int id)
- {
- final String right = Integer.toHexString(id).toUpperCase();
- final int zeroedLength = 64 - right.length();
- return Strings.repeat("0", zeroedLength) + right;
- }
-}
diff --git a/src/test/java/com/notnoop/apns/utils/Simulator/FailingApnsServerSimulator.java b/src/test/java/com/notnoop/apns/utils/Simulator/FailingApnsServerSimulator.java
deleted file mode 100644
index dda34b56..00000000
--- a/src/test/java/com/notnoop/apns/utils/Simulator/FailingApnsServerSimulator.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.utils.Simulator;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.net.ServerSocketFactory;
-import java.io.IOException;
-import java.util.List;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-
-/**
- * A Server simulator that can simulate some failure modes.
- */
-public class FailingApnsServerSimulator extends ApnsServerSimulator {
-
- private static final Logger logger = LoggerFactory.getLogger(FailingApnsServerSimulator.class);
-
-
- private BlockingQueue queue = new LinkedBlockingQueue();
-
- public FailingApnsServerSimulator(final ServerSocketFactory sslFactory) {
- super(sslFactory);
- }
-
- @Override
- protected void onNotification(final ApnsServerSimulator.Notification notification, final InputOutputSocket inputOutputSocket)
- throws IOException {
- logger.debug("Queueing notification " + notification);
- queue.add(notification);
- final byte[] token = notification.getDeviceToken();
- if (token.length == 32 && token[0] == (byte)0xff && token[1] == (byte)0xff) {
- switch (token[2]) {
- case 0:
- fail(token[3], notification.getIdentifier(), inputOutputSocket);
- break;
-
- case 1:
- try {
- final int millis = token[3] * 100;
- Thread.sleep(millis);
- } catch (InterruptedException e) {
- Thread.interrupted();
- }
- break;
-
- case 2:
- default:
- inputOutputSocket.close();
- break;
- }
-
- }
- }
-
- protected List getBadTokens() {
- return super.getBadTokens();
- }
-
- public BlockingQueue getQueue() {
- return queue;
- }
-
-}
diff --git a/src/test/java/com/notnoop/apns/utils/Simulator/InputOutputSocket.java b/src/test/java/com/notnoop/apns/utils/Simulator/InputOutputSocket.java
deleted file mode 100644
index 8170c523..00000000
--- a/src/test/java/com/notnoop/apns/utils/Simulator/InputOutputSocket.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.utils.Simulator;
-
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.net.Socket;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Wrap some of the boilerplate code using socket, enable passing around a socket together with its streams.
- */
-public class InputOutputSocket {
- private static final Logger LOGGER = LoggerFactory.getLogger(InputOutputSocket.class);
- private final Socket socket;
- private final ApnsInputStream inputStream;
- private final DataOutputStream outputStream;
-
- public InputOutputSocket(final Socket socket) throws IOException {
- if (socket == null) {
- throw new NullPointerException("socket may not be null");
- }
-
- this.socket = socket;
-
- // Hack, work around JVM deadlock ... https://community.oracle.com/message/10989561#10989561
- socket.setSoLinger(true, 1);
- outputStream = new DataOutputStream(socket.getOutputStream());
- inputStream = new ApnsInputStream(socket.getInputStream());
- }
-
- public Socket getSocket() {
- return socket;
- }
-
- public ApnsInputStream getInputStream() {
- return inputStream;
- }
-
- /*
- public DataOutputStream getOutputStream() {
- return outputStream;
- }
- */
-
-
-
- public synchronized void close() {
- try {
- inputStream.close();
- } catch (IOException e) {
- LOGGER.warn("Can not close inputStream properly", e);
- }
-
- try {
- outputStream.close();
- } catch (IOException e) {
- LOGGER.warn("Can not close outputStream properly", e);
- }
-
- try {
- socket.close();
- } catch (IOException e) {
- LOGGER.warn("Can not close socket properly", e);
- }
- }
-
- /**
- * Write data to the output stream while synchronized against close(). This hopefully fixes
- * sporadic test failures caused by a deadlock of write() and close()
- * @param bytes The data to write
- * @throws IOException if an error occurs
- */
- public void syncWrite(byte[] bytes) throws IOException {
- outputStream.write(bytes);
- outputStream.flush();
- }
-}
diff --git a/src/test/java/com/notnoop/apns/utils/StringTruncationTest.java b/src/test/java/com/notnoop/apns/utils/StringTruncationTest.java
deleted file mode 100644
index 275e50e8..00000000
--- a/src/test/java/com/notnoop/apns/utils/StringTruncationTest.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.utils;
-
-import org.junit.Assert;
-
-import org.junit.experimental.theories.DataPoints;
-import org.junit.experimental.theories.Theories;
-import org.junit.experimental.theories.Theory;
-import org.junit.runner.RunWith;
-
-import com.notnoop.apns.internal.Utilities;
-
-// Test inspired by http://stackoverflow.com/questions/119328/how-do-i-truncate-a-java-string-to-fit-in-a-given-number-of-bytes-once-utf-8-enc
-@RunWith(Theories.class)
-public class StringTruncationTest {
- @DataPoints public static Object[][] dataPoints = {
- {"abcd", 0, 0},
- {"abcd", 1, 1},
- {"abcd", 2, 2},
- {"abcd", 3, 3},
- {"abcd", 4, 4},
- {"abcd", 5, 4},
-
- {"a\u0080b", 0, 0},
- {"a\u0080b", 1, 1},
- {"a\u0080b", 2, 1},
- {"a\u0080b", 3, 3},
- {"a\u0080b", 4, 4},
- {"a\u0080b", 5, 4},
-
- {"a\u0800b", 0, 0},
- {"a\u0800b", 1, 1},
- {"a\u0800b", 2, 1},
- {"a\u0800b", 3, 1},
- {"a\u0800b", 4, 4},
- {"a\u0800b", 5, 5},
- {"a\u0800b", 6, 5},
- };
-
- @DataPoints public static Object[][] surrogatePairs = {
- {"\uD834\uDD1E", 0, 0},
- {"\uD834\uDD1E", 1, 0},
- {"\uD834\uDD1E", 2, 0},
- {"\uD834\uDD1E", 3, 0},
- {"\uD834\uDD1E", 4, 4},
- {"\uD834\uDD1E", 5, 4}
- };
-
- @Theory
- public void truncateUTF8Properly(Object[] p) {
- String str = (String)p[0];
- int maxBytes = (Integer)p[1];
- int expectedBytes = (Integer)p[2];
-
- String result = Utilities.truncateWhenUTF8(str, maxBytes);
- byte[] utf8 = Utilities.toUTF8Bytes(result);
-
- Assert.assertEquals(expectedBytes, utf8.length);
- }
-}
diff --git a/src/test/java/com/notnoop/apns/utils/junit/DumpThreadsOnErrorRule.java b/src/test/java/com/notnoop/apns/utils/junit/DumpThreadsOnErrorRule.java
deleted file mode 100644
index 9ac5565d..00000000
--- a/src/test/java/com/notnoop/apns/utils/junit/DumpThreadsOnErrorRule.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.utils.junit;
-
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import java.util.Map;
-
-public class DumpThreadsOnErrorRule implements TestRule {
-
- @Override
- public Statement apply(Statement base, Description description) {
- return new DumpThreadsStatement(base);
- }
-
- private static class DumpThreadsStatement extends Statement {
-
- private final Statement base;
-
- private DumpThreadsStatement(Statement base) {
- this.base = base;
- }
-
- @Override
- public void evaluate() throws Throwable {
- try {
- base.evaluate();
- } catch (Throwable t) {
- dumpAllThreads();
- throw t;
- }
- }
-
- private void dumpAllThreads() {
- Map liveThreads = Thread.getAllStackTraces();
- for (Object o : liveThreads.keySet()) {
- Thread key = (Thread) o;
- System.err.println("\nThread " + key.getName());
- StackTraceElement[] trace = (StackTraceElement[]) liveThreads.get(key);
- for (StackTraceElement aTrace : trace) {
- System.err.println("\tat " + aTrace);
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/test/java/com/notnoop/apns/utils/junit/Repeat.java b/src/test/java/com/notnoop/apns/utils/junit/Repeat.java
deleted file mode 100644
index 382ace30..00000000
--- a/src/test/java/com/notnoop/apns/utils/junit/Repeat.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.utils.junit;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target({java.lang.annotation.ElementType.METHOD})
-public @interface Repeat {
- public abstract int count();
-}
diff --git a/src/test/java/com/notnoop/apns/utils/junit/RepeatRule.java b/src/test/java/com/notnoop/apns/utils/junit/RepeatRule.java
deleted file mode 100644
index eeababe9..00000000
--- a/src/test/java/com/notnoop/apns/utils/junit/RepeatRule.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2009, Mahmood Ali.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Mahmood Ali. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.notnoop.apns.utils.junit;
-
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-public class RepeatRule implements TestRule {
-
- @Override
- public Statement apply(Statement base, Description description) {
- Repeat repeat = description.getAnnotation(Repeat.class);
- if (repeat != null) {
- return new RepeatStatement(repeat.count(), base);
- }
- return base;
- }
-
- private static class RepeatStatement extends Statement {
-
- private final int count;
- private final Statement base;
-
- private RepeatStatement(int count, Statement base) {
- this.count = count;
- this.base = base;
- }
-
- @Override
- public void evaluate() throws Throwable {
- for (int i = count; i > 0; i--) {
- base.evaluate();
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/test/resources/clientStore.jks b/src/test/resources/clientStore.jks
deleted file mode 100644
index 8564ff4a..00000000
Binary files a/src/test/resources/clientStore.jks and /dev/null differ
diff --git a/src/test/resources/clientStore.p12 b/src/test/resources/clientStore.p12
deleted file mode 100644
index ef8243e1..00000000
Binary files a/src/test/resources/clientStore.p12 and /dev/null differ
diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml
deleted file mode 100644
index a48239f3..00000000
--- a/src/test/resources/logback-test.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/src/test/resources/serverStore.p12 b/src/test/resources/serverStore.p12
deleted file mode 100644
index 80806269..00000000
Binary files a/src/test/resources/serverStore.p12 and /dev/null differ
diff --git a/src/test/resources/serverTrustStore.p12 b/src/test/resources/serverTrustStore.p12
deleted file mode 100644
index 458b8b63..00000000
Binary files a/src/test/resources/serverTrustStore.p12 and /dev/null differ
diff --git a/stresstest.sh b/stresstest.sh
deleted file mode 100755
index 5410b6eb..00000000
--- a/stresstest.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/sh
-rm builds.logs
-while mvn clean install; do date >>builds.log; done
diff --git a/template.mf b/template.mf
deleted file mode 100644
index aca149c3..00000000
--- a/template.mf
+++ /dev/null
@@ -1,8 +0,0 @@
-Bundle-Name: com.notnoop.apns
-Bundle-ManifestVersion: 2
-Import-Template:
- org.slf4j.*;version="0",
- com.fasterxml.jackson.*;version="0",
- javax.net.*;version="0",
- edu.umd.cs.findbugs.annotations.*;version="0",
- org.apache.*;version="0"
diff --git a/tools/generate_test_stores.sh b/tools/generate_test_stores.sh
deleted file mode 100644
index 2d3899b5..00000000
--- a/tools/generate_test_stores.sh
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/bin/bash
-
-KEYSIZE=1024
-VALIDITY=1460
-rm -f serverStore.p12 serverTrustStore.p12 caKey.pem caCert.pem request.crs clientStore.p12 clientCert.crt clientStore.jks
-
-echo ---=== Generating Certificates ===---
-echo This tools will request several parameters.
-echo The names are free, but it is recommended
-echo to enter a name that identifies the certificate
-echo for example TestServer, TestCA, TestClient, TestInvalidClient
-echo Enter 123456 when asked for a password
-echo
-
-# Server Cert
-echo --== Generating Server Certificate ==--
-keytool -genkey -keyalg RSA -alias notnoop-server \
- -keystore serverStore.p12 -storepass 123456 -storetype PKCS12 \
- -validity ${VALIDITY} -keysize ${KEYSIZE}
-keytool -exportcert -alias notnoop-server \
- -keystore serverStore.p12 -storepass 123456 -storetype PKCS12 | keytool -printcert
-
-# Client Cert CA
-echo --== Generating Client CA Certificate ==--
-keytool -genkey -keyalg RSA -alias notnoop-ca \
- -keystore serverTrustStore.p12 -storetype pkcs12 -storepass 123456 \
- -validity ${VALIDITY} -keysize ${KEYSIZE}
-keytool -exportcert -alias notnoop-ca \
- -keystore serverTrustStore.p12 -storepass 123456 -storetype PKCS12 | keytool -printcert
-
-openssl pkcs12 -in serverTrustStore.p12 -nocerts -out caKey.pem
-openssl pkcs12 -in serverTrustStore.p12 -clcerts -nokeys -out caCert.pem
-
-echo --== Generating Client Certificate ==--
-keytool -genkey -keyalg RSA -keystore clientStore.p12 -storepass 123456 -storetype PKCS12 -alias notnoop-client \
- -validity ${VALIDITY} -keysize ${KEYSIZE}
-keytool -certreq -keystore clientStore.p12 -storepass 123456 -storetype PKCS12 -alias notnoop-client -file request.crs
-
-echo --== Signing Client Certificate with CA ==--
-openssl x509 -req -CA CACert.pem -CAkey CAKey.pem -in request.crs -out clientCert.crt \
- -days ${VALIDITY} -CAcreateserial -outform PEM -set_serial 1
-cat caCert.pem >> clientCert.crt
-keytool -import -keystore clientStore.p12 -storepass 123456 -storetype PKCS12 -file clientCert.crt -alias notnoop-client
-keytool -exportcert -alias notnoop-client \
- -keystore clientStore.p12 -storepass 123456 -storetype PKCS12 | keytool -printcert
-
-echo --== Generating JKS Client Keystore with Client Certificate ==--
-keytool -importkeystore \
- -srckeystore clientStore.p12 -srcstorepass 123456 -srcstoretype PKCS12 -srcalias notnoop-client \
- -destkeystore clientStore.jks -deststorepass 123456 -deststoretype JKS -destalias notnoop-client
-
-echo --== Generating Invalid Client Certificate ==--
-keytool -genkeypair -keyalg RSA -keystore clientStore.jks -storepass 123456 -storetype JKS -alias notused
-
-keytool -list -keystore clientStore.jks -storepass 123456 -storetype JKS
-
-rm caKey.pem caCert.pem request.crs clientCert.crt
\ No newline at end of file