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
}
}
}
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);
}
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);
}
}
Aggregations