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 100755
index abc01f3..0000000
--- 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 100755
index 4ba33f6..0000000
--- 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 100755
index b5b2661..0000000
--- a/src/main/java/com/notnoop/apns/EnhancedApnsNotification.java
+++ /dev/null
@@ -1,191 +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;
- private String deviceId;
-
- public void setDeviceId(String deviceId) {
- this.deviceId = deviceId;
- }
-
- 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();
- }
-
- @Override
- public String getDeviceId() {
- return deviceId;
- }
-
- /**
- * 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 100755
index 798c22a..0000000
--- 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 100755
index bff7dd9..0000000
--- 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 100755
index 6c2dad7..0000000
--- a/src/main/java/com/notnoop/apns/SimpleApnsNotification.java
+++ /dev/null
@@ -1,172 +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+")";
- }
-
- @Override
- public String getDeviceId() {
- return null;
- }
-}
diff --git a/src/main/java/com/notnoop/apns/StartSendingApnsDelegate.java b/src/main/java/com/notnoop/apns/StartSendingApnsDelegate.java
deleted file mode 100755
index cf7d957..0000000
--- 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 100755
index 5a721e9..0000000
--- a/src/main/java/com/notnoop/apns/internal/AbstractApnsService.java
+++ /dev/null
@@ -1,90 +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, String deviceId) throws NetworkIOException {
- EnhancedApnsNotification notification =
- new EnhancedApnsNotification(c.incrementAndGet(), EnhancedApnsNotification.MAXIMUM_EXPIRY, deviceToken, payload);
- notification.setDeviceId(deviceId);
- push(notification);
- return notification;
- }
-
- public EnhancedApnsNotification push(String deviceToken, String payload, Date expiry, String deviceId) throws NetworkIOException {
- EnhancedApnsNotification notification =
- new EnhancedApnsNotification(c.incrementAndGet(), (int)(expiry.getTime() / 1000), deviceToken, payload);
- notification.setDeviceId(deviceId);
- push(notification);
- return notification;
- }
-
- public EnhancedApnsNotification push(byte[] deviceToken, byte[] payload, String deviceId) throws NetworkIOException {
- EnhancedApnsNotification notification =
- new EnhancedApnsNotification(c.incrementAndGet(), EnhancedApnsNotification.MAXIMUM_EXPIRY, deviceToken, payload);
- notification.setDeviceId(deviceId);
- push(notification);
- return notification;
- }
-
- public EnhancedApnsNotification push(byte[] deviceToken, byte[] payload, int expiry, String deviceId) throws NetworkIOException {
- EnhancedApnsNotification notification =
- new EnhancedApnsNotification(c.incrementAndGet(), expiry, deviceToken, payload);
- notification.setDeviceId(deviceId);
- push(notification);
- return notification;
- }
-
- 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 100755
index 757a81b..0000000
--- 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 100755
index 825aea3..0000000
--- 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 100755
index 26db208..0000000
--- 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 100755
index e27d170..0000000
--- 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 100755
index 387f5a8..0000000
--- 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 100755
index d7dcbef..0000000
--- 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 100755
index 21cc820..0000000
--- 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 100755
index b6a70eb..0000000
--- 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 100755
index 5175bfd..0000000
--- 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 100755
index 5e0d68c..0000000
--- 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 100755
index 1849098..0000000
--- 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 100755
index c9b3bea..0000000
--- 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 100755
index f1725e5..0000000
--- 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 100755
index be97578..0000000
--- 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 100755
index df84eb5..0000000
--- 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 100755
index 1a447bd..0000000
--- 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/main/resources/application.properties b/src/main/resources/application.properties
index a30a91f..0d50fc1 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1 +1,3 @@
-server.port=8085
\ No newline at end of file
+server.port=8085
+logging.level.root=debug
+logging.file=push.log