Search in sources :

Example 1 with Outcome

use of org.apache.qpid.proton.amqp.messaging.Outcome in project azure-service-bus-java by Azure.

the class CoreMessageReceiver method onReceiveComplete.

@Override
public void onReceiveComplete(Delivery delivery) {
    this.underlyingFactory.getRetryPolicy().resetRetryCount(this.getClientId());
    byte[] deliveryTag = delivery.getTag();
    String deliveryTagAsString = StringUtil.convertBytesToString(delivery.getTag());
    TRACE_LOGGER.debug("Received a delivery '{}' from '{}'", deliveryTagAsString, this.receivePath);
    if (deliveryTag == null || deliveryTag.length == 0 || !this.tagsToDeliveriesMap.containsKey(deliveryTagAsString)) {
        TRACE_LOGGER.debug("Received a message from '{}'. Adding to prefecthed messages.", this.receivePath);
        try {
            Message message = Util.readMessageFromDelivery(receiveLink, delivery);
            if (this.settleModePair.getSenderSettleMode() == SenderSettleMode.SETTLED) {
                // No op. Delivery comes settled from the sender
                delivery.disposition(Accepted.getInstance());
                delivery.settle();
            } else {
                this.tagsToDeliveriesMap.put(StringUtil.convertBytesToString(delivery.getTag()), delivery);
                receiveLink.advance();
            }
            // Accuracy of count is not that important. So not making those two operations atomic
            this.currentPrefetechedMessagesCount.incrementAndGet();
            this.prefetchedMessages.add(new MessageWithDeliveryTag(message, delivery.getTag()));
        } catch (Exception e) {
            TRACE_LOGGER.warn("Reading message from delivery '{}' from '{}', session '{}' failed with unexpected exception.", deliveryTagAsString, this.receivePath, this.sessionId, e);
            delivery.disposition(Released.getInstance());
            delivery.settle();
            return;
        }
    } else {
        DeliveryState remoteState = delivery.getRemoteState();
        TRACE_LOGGER.debug("Received a delivery '{}' with state '{}' from '{}'", deliveryTagAsString, remoteState, this.receivePath);
        if (remoteState instanceof Outcome) {
            Outcome remoteOutcome = (Outcome) remoteState;
            UpdateStateWorkItem matchingUpdateStateWorkItem = this.pendingUpdateStateRequests.get(deliveryTagAsString);
            if (matchingUpdateStateWorkItem != null) {
                // This comparison is ugly. Using it for the lack of equals operation on Outcome classes
                if (remoteOutcome.getClass().getName().equals(matchingUpdateStateWorkItem.outcome.getClass().getName())) {
                    TRACE_LOGGER.debug("Completing a pending updateState operation for delivery '{}' from '{}'", deliveryTagAsString, this.receivePath);
                    this.completePendingUpdateStateWorkItem(delivery, deliveryTagAsString, matchingUpdateStateWorkItem, null);
                } else {
                    // if(matchingUpdateStateWorkItem.expectedOutcome instanceof Accepted)
                    // {
                    TRACE_LOGGER.warn("Received delivery '{}' state '{}' doesn't match expected state '{}'", deliveryTagAsString, remoteState, matchingUpdateStateWorkItem.outcome);
                    // Complete requests
                    if (remoteOutcome instanceof Rejected) {
                        Rejected rejected = (Rejected) remoteOutcome;
                        ErrorCondition error = rejected.getError();
                        Exception exception = ExceptionUtil.toException(error);
                        if (ExceptionUtil.isGeneralError(error.getCondition())) {
                            this.lastKnownLinkError = exception;
                            this.lastKnownErrorReportedAt = Instant.now();
                        }
                        Duration retryInterval = this.retryPolicy.getNextRetryInterval(this.getClientId(), exception, matchingUpdateStateWorkItem.getTimeoutTracker().remaining());
                        if (retryInterval == null) {
                            TRACE_LOGGER.error("Completing pending updateState operation for delivery '{}' with exception", deliveryTagAsString, exception);
                            this.completePendingUpdateStateWorkItem(delivery, deliveryTagAsString, matchingUpdateStateWorkItem, exception);
                        } else {
                            matchingUpdateStateWorkItem.setLastKnownException(exception);
                            // Retry after retry interval
                            TRACE_LOGGER.debug("Pending updateState operation for delivery '{}' will be retried after '{}'", deliveryTagAsString, retryInterval);
                            try {
                                this.underlyingFactory.scheduleOnReactorThread((int) retryInterval.toMillis(), new DispatchHandler() {

                                    @Override
                                    public void onEvent() {
                                        delivery.disposition((DeliveryState) matchingUpdateStateWorkItem.getOutcome());
                                    }
                                });
                            } catch (IOException ioException) {
                                this.completePendingUpdateStateWorkItem(delivery, deliveryTagAsString, matchingUpdateStateWorkItem, new ServiceBusException(false, "Operation failed while scheduling a retry on Reactor, see cause for more details.", ioException));
                            }
                        }
                    } else if (remoteOutcome instanceof Released) {
                        Exception exception = new OperationCancelledException(remoteOutcome.toString());
                        TRACE_LOGGER.error("Completing pending updateState operation for delivery '{}' with exception", deliveryTagAsString, exception);
                        this.completePendingUpdateStateWorkItem(delivery, deliveryTagAsString, matchingUpdateStateWorkItem, exception);
                    } else {
                        Exception exception = new ServiceBusException(false, remoteOutcome.toString());
                        TRACE_LOGGER.error("Completing pending updateState operation for delivery '{}' with exception", deliveryTagAsString, exception);
                        this.completePendingUpdateStateWorkItem(delivery, deliveryTagAsString, matchingUpdateStateWorkItem, exception);
                    }
                // }
                }
            } else {
            // Should not happen. Ignore it
            }
        } else {
        // Ignore it. we are only interested in terminal delivery states
        }
    }
}
Also used : Released(org.apache.qpid.proton.amqp.messaging.Released) Message(org.apache.qpid.proton.message.Message) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) DispatchHandler(com.microsoft.azure.servicebus.amqp.DispatchHandler) Duration(java.time.Duration) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) IOException(java.io.IOException) IOException(java.io.IOException) DeliveryState(org.apache.qpid.proton.amqp.transport.DeliveryState) Outcome(org.apache.qpid.proton.amqp.messaging.Outcome)

Example 2 with Outcome

use of org.apache.qpid.proton.amqp.messaging.Outcome in project activemq-artemis by apache.

the class AmqpSender method processDeliveryUpdates.

@Override
public void processDeliveryUpdates(AmqpConnection connection, Delivery updated) throws IOException {
    List<Delivery> toRemove = new ArrayList<>();
    for (Delivery delivery : pending) {
        DeliveryState state = delivery.getRemoteState();
        if (state == null) {
            continue;
        }
        doDeliveryUpdateInspection(delivery);
        Outcome outcome = null;
        if (state instanceof TransactionalState) {
            LOG.trace("State of delivery is Transactional, retrieving outcome: {}", state);
            outcome = ((TransactionalState) state).getOutcome();
        } else if (state instanceof Outcome) {
            outcome = (Outcome) state;
        } else {
            LOG.warn("Message send updated with unsupported state: {}", state);
            outcome = null;
        }
        AsyncResult request = (AsyncResult) delivery.getContext();
        Exception deliveryError = null;
        if (outcome instanceof Accepted) {
            LOG.trace("Outcome of delivery was accepted: {}", delivery);
            if (request != null && !request.isComplete()) {
                request.onSuccess();
            }
        } else if (outcome instanceof Rejected) {
            LOG.trace("Outcome of delivery was rejected: {}", delivery);
            ErrorCondition remoteError = ((Rejected) outcome).getError();
            if (remoteError == null) {
                remoteError = getEndpoint().getRemoteCondition();
            }
            deliveryError = AmqpSupport.convertToException(remoteError);
        } else if (outcome instanceof Released) {
            LOG.trace("Outcome of delivery was released: {}", delivery);
            deliveryError = new IOException("Delivery failed: released by receiver");
        } else if (outcome instanceof Modified) {
            LOG.trace("Outcome of delivery was modified: {}", delivery);
            deliveryError = new IOException("Delivery failed: failure at remote");
        }
        if (deliveryError != null) {
            if (request != null && !request.isComplete()) {
                request.onFailure(deliveryError);
            } else {
                connection.fireClientException(deliveryError);
            }
        }
        tagGenerator.returnTag(delivery.getTag());
        delivery.settle();
        toRemove.add(delivery);
    }
    pending.removeAll(toRemove);
}
Also used : Released(org.apache.qpid.proton.amqp.messaging.Released) Modified(org.apache.qpid.proton.amqp.messaging.Modified) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) ArrayList(java.util.ArrayList) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) IOException(java.io.IOException) InvalidDestinationException(javax.jms.InvalidDestinationException) IOException(java.io.IOException) Accepted(org.apache.qpid.proton.amqp.messaging.Accepted) TransactionalState(org.apache.qpid.proton.amqp.transaction.TransactionalState) DeliveryState(org.apache.qpid.proton.amqp.transport.DeliveryState) Outcome(org.apache.qpid.proton.amqp.messaging.Outcome) Delivery(org.apache.qpid.proton.engine.Delivery) AsyncResult(org.apache.activemq.transport.amqp.client.util.AsyncResult)

Example 3 with Outcome

use of org.apache.qpid.proton.amqp.messaging.Outcome in project activemq-artemis by apache.

the class ProtonServerSenderContext method onMessage.

@Override
public void onMessage(Delivery delivery) throws ActiveMQAMQPException {
    if (closed) {
        return;
    }
    OperationContext oldContext = sessionSPI.recoverContext();
    try {
        Message message = ((MessageReference) delivery.getContext()).getMessage();
        boolean preSettle = sender.getRemoteSenderSettleMode() == SenderSettleMode.SETTLED;
        DeliveryState remoteState;
        connection.lock();
        try {
            remoteState = delivery.getRemoteState();
        } finally {
            connection.unlock();
        }
        boolean settleImmediate = true;
        if (remoteState instanceof Accepted) {
            // acking again would show an exception but would have no negative effect but best to handle anyway.
            if (delivery.isSettled()) {
                return;
            }
            // from dealer, a perf hit but a must
            try {
                sessionSPI.ack(null, brokerConsumer, message);
            } catch (Exception e) {
                log.warn(e.toString(), e);
                throw ActiveMQAMQPProtocolMessageBundle.BUNDLE.errorAcknowledgingMessage(message.toString(), e.getMessage());
            }
        } else if (remoteState instanceof TransactionalState) {
            // When the message arrives with a TransactionState disposition the ack should
            // enlist the message into the transaction associated with the given txn ID.
            TransactionalState txState = (TransactionalState) remoteState;
            ProtonTransactionImpl tx = (ProtonTransactionImpl) this.sessionSPI.getTransaction(txState.getTxnId(), false);
            if (txState.getOutcome() != null) {
                settleImmediate = false;
                Outcome outcome = txState.getOutcome();
                if (outcome instanceof Accepted) {
                    if (!delivery.remotelySettled()) {
                        TransactionalState txAccepted = new TransactionalState();
                        txAccepted.setOutcome(Accepted.getInstance());
                        txAccepted.setTxnId(txState.getTxnId());
                        connection.lock();
                        try {
                            delivery.disposition(txAccepted);
                        } finally {
                            connection.unlock();
                        }
                    }
                    // from dealer, a perf hit but a must
                    try {
                        sessionSPI.ack(tx, brokerConsumer, message);
                        tx.addDelivery(delivery, this);
                    } catch (Exception e) {
                        throw ActiveMQAMQPProtocolMessageBundle.BUNDLE.errorAcknowledgingMessage(message.toString(), e.getMessage());
                    }
                }
            }
        } else if (remoteState instanceof Released) {
            try {
                sessionSPI.cancel(brokerConsumer, message, false);
            } catch (Exception e) {
                throw ActiveMQAMQPProtocolMessageBundle.BUNDLE.errorCancellingMessage(message.toString(), e.getMessage());
            }
        } else if (remoteState instanceof Rejected) {
            try {
                sessionSPI.reject(brokerConsumer, message);
            } catch (Exception e) {
                throw ActiveMQAMQPProtocolMessageBundle.BUNDLE.errorCancellingMessage(message.toString(), e.getMessage());
            }
        } else if (remoteState instanceof Modified) {
            try {
                Modified modification = (Modified) remoteState;
                if (Boolean.TRUE.equals(modification.getUndeliverableHere())) {
                    message.rejectConsumer(brokerConsumer.sequentialID());
                }
                if (Boolean.TRUE.equals(modification.getDeliveryFailed())) {
                    sessionSPI.cancel(brokerConsumer, message, true);
                } else {
                    sessionSPI.cancel(brokerConsumer, message, false);
                }
            } catch (Exception e) {
                throw ActiveMQAMQPProtocolMessageBundle.BUNDLE.errorCancellingMessage(message.toString(), e.getMessage());
            }
        } else {
            log.debug("Received null or unknown disposition for delivery update: " + remoteState);
            return;
        }
        if (!preSettle) {
            protonSession.replaceTag(delivery.getTag());
        }
        if (settleImmediate) {
            settle(delivery);
        }
    } finally {
        sessionSPI.afterIO(new IOCallback() {

            @Override
            public void done() {
                connection.flush();
            }

            @Override
            public void onError(int errorCode, String errorMessage) {
                connection.flush();
            }
        });
        sessionSPI.resetContext(oldContext);
    }
}
Also used : OperationContext(org.apache.activemq.artemis.core.persistence.OperationContext) Released(org.apache.qpid.proton.amqp.messaging.Released) Modified(org.apache.qpid.proton.amqp.messaging.Modified) AMQPMessage(org.apache.activemq.artemis.protocol.amqp.broker.AMQPMessage) Message(org.apache.activemq.artemis.api.core.Message) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) SimpleString(org.apache.activemq.artemis.api.core.SimpleString) MessageReference(org.apache.activemq.artemis.core.server.MessageReference) IOCallback(org.apache.activemq.artemis.core.io.IOCallback) Accepted(org.apache.qpid.proton.amqp.messaging.Accepted) ActiveMQAMQPNotFoundException(org.apache.activemq.artemis.protocol.amqp.exceptions.ActiveMQAMQPNotFoundException) ActiveMQAMQPException(org.apache.activemq.artemis.protocol.amqp.exceptions.ActiveMQAMQPException) FilterException(org.apache.activemq.artemis.selector.filter.FilterException) ActiveMQAMQPInternalErrorException(org.apache.activemq.artemis.protocol.amqp.exceptions.ActiveMQAMQPInternalErrorException) ActiveMQQueueExistsException(org.apache.activemq.artemis.api.core.ActiveMQQueueExistsException) ActiveMQAMQPResourceLimitExceededException(org.apache.activemq.artemis.protocol.amqp.exceptions.ActiveMQAMQPResourceLimitExceededException) ActiveMQAMQPIllegalStateException(org.apache.activemq.artemis.protocol.amqp.exceptions.ActiveMQAMQPIllegalStateException) ActiveMQSecurityException(org.apache.activemq.artemis.api.core.ActiveMQSecurityException) TransactionalState(org.apache.qpid.proton.amqp.transaction.TransactionalState) DeliveryState(org.apache.qpid.proton.amqp.transport.DeliveryState) Outcome(org.apache.qpid.proton.amqp.messaging.Outcome) ProtonTransactionImpl(org.apache.activemq.artemis.protocol.amqp.proton.transaction.ProtonTransactionImpl)

Aggregations

Outcome (org.apache.qpid.proton.amqp.messaging.Outcome)3 Rejected (org.apache.qpid.proton.amqp.messaging.Rejected)3 Released (org.apache.qpid.proton.amqp.messaging.Released)3 DeliveryState (org.apache.qpid.proton.amqp.transport.DeliveryState)3 IOException (java.io.IOException)2 Accepted (org.apache.qpid.proton.amqp.messaging.Accepted)2 Modified (org.apache.qpid.proton.amqp.messaging.Modified)2 TransactionalState (org.apache.qpid.proton.amqp.transaction.TransactionalState)2 ErrorCondition (org.apache.qpid.proton.amqp.transport.ErrorCondition)2 DispatchHandler (com.microsoft.azure.servicebus.amqp.DispatchHandler)1 Duration (java.time.Duration)1 ArrayList (java.util.ArrayList)1 InvalidDestinationException (javax.jms.InvalidDestinationException)1 ActiveMQQueueExistsException (org.apache.activemq.artemis.api.core.ActiveMQQueueExistsException)1 ActiveMQSecurityException (org.apache.activemq.artemis.api.core.ActiveMQSecurityException)1 Message (org.apache.activemq.artemis.api.core.Message)1 SimpleString (org.apache.activemq.artemis.api.core.SimpleString)1 IOCallback (org.apache.activemq.artemis.core.io.IOCallback)1 OperationContext (org.apache.activemq.artemis.core.persistence.OperationContext)1 MessageReference (org.apache.activemq.artemis.core.server.MessageReference)1