Search in sources :

Example 1 with ApnsDeliveryErrorException

use of com.notnoop.exceptions.ApnsDeliveryErrorException in project java-apns by notnoop.

the class ApnsConnectionResendTest method testGivenFailedSubmissionDueToErrorThenApnsDownWithNotificationsInBufferEnsureClientNotified.

/*
     * Test when we submit 3 messages to APNS 0, 1, 2.  0 is an error but we don't see the error response back until
     * 1,2 have already been submitted.  Then at this point the network connection to APNS cannot be made, so that
     * when retrying the submissions we have to notify the client that delivery failed for 1 and 2.
     */
@Test
public void testGivenFailedSubmissionDueToErrorThenApnsDownWithNotificationsInBufferEnsureClientNotified() throws Exception {
    final DeliveryError deliveryError = DeliveryError.INVALID_PAYLOAD_SIZE;
    apnsSim.when(NOTIFICATION_0).thenDoNothing();
    apnsSim.when(NOTIFICATION_1).thenDoNothing();
    apnsSim.when(NOTIFICATION_2).thenRespond(ApnsResponse.returnErrorAndShutdown(deliveryError, NOTIFICATION_0));
    testee.push(NOTIFICATION_0);
    testee.push(NOTIFICATION_1);
    testee.push(NOTIFICATION_2);
    // Give some time for connection failure to take place
    Thread.sleep(5000);
    // Verify received expected notifications
    apnsSim.verify();
    // verify delegate calls
    assertEquals(3, delegateRecorder.getSent().size());
    final List<MessageSentFailedRecord> failed = delegateRecorder.getFailed();
    assertEquals(3, failed.size());
    // first is failed delivery due to payload size
    failed.get(0).assertRecord(NOTIFICATION_0, new ApnsDeliveryErrorException(deliveryError));
    // second and third are due to not being able to connect to APNS
    assertNetworkIoExForRedelivery(NOTIFICATION_1, failed.get(1));
    assertNetworkIoExForRedelivery(NOTIFICATION_2, failed.get(2));
}
Also used : MessageSentFailedRecord(com.notnoop.apns.integration.ApnsDelegateRecorder.MessageSentFailedRecord) DeliveryError(com.notnoop.apns.DeliveryError) ApnsDeliveryErrorException(com.notnoop.exceptions.ApnsDeliveryErrorException) Test(org.junit.Test)

Example 2 with ApnsDeliveryErrorException

use of com.notnoop.exceptions.ApnsDeliveryErrorException in project java-apns by notnoop.

the class ApnsConnectionImpl method monitorSocket.

private void monitorSocket(final Socket socketToMonitor) {
    logger.debug("Launching Monitoring Thread for socket {}", socketToMonitor);
    Thread t = threadFactory.newThread(new Runnable() {

        static final 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<ApnsNotification> tempCache = new LinkedList<ApnsNotification>();
                    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();
}
Also used : InputStream(java.io.InputStream) ApnsNotification(com.notnoop.apns.ApnsNotification) EnhancedApnsNotification(com.notnoop.apns.EnhancedApnsNotification) NetworkIOException(com.notnoop.exceptions.NetworkIOException) IOException(java.io.IOException) DeliveryError(com.notnoop.apns.DeliveryError) EOFException(java.io.EOFException) Queue(java.util.Queue) ConcurrentLinkedQueue(java.util.concurrent.ConcurrentLinkedQueue) ApnsDeliveryErrorException(com.notnoop.exceptions.ApnsDeliveryErrorException)

Aggregations

DeliveryError (com.notnoop.apns.DeliveryError)2 ApnsDeliveryErrorException (com.notnoop.exceptions.ApnsDeliveryErrorException)2 ApnsNotification (com.notnoop.apns.ApnsNotification)1 EnhancedApnsNotification (com.notnoop.apns.EnhancedApnsNotification)1 MessageSentFailedRecord (com.notnoop.apns.integration.ApnsDelegateRecorder.MessageSentFailedRecord)1 NetworkIOException (com.notnoop.exceptions.NetworkIOException)1 EOFException (java.io.EOFException)1 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 Queue (java.util.Queue)1 ConcurrentLinkedQueue (java.util.concurrent.ConcurrentLinkedQueue)1 Test (org.junit.Test)1