use of org.apache.qpid.proton.amqp.messaging.Rejected in project hono by eclipse.
the class TelemetrySenderImplTest method testSendMessageDoesNotWaitForAcceptedOutcome.
/**
* Verifies that the sender does not wait for the peer to settle and
* accept a message before succeeding.
*
* @param ctx The vert.x test context.
*/
@SuppressWarnings({ "unchecked" })
@Test
public void testSendMessageDoesNotWaitForAcceptedOutcome(final TestContext ctx) {
// GIVEN a sender that has credit
when(sender.sendQueueFull()).thenReturn(Boolean.FALSE);
MessageSender messageSender = new TelemetrySenderImpl(config, sender, "tenant", "telemetry/tenant", context);
final AtomicReference<Handler<ProtonDelivery>> handlerRef = new AtomicReference<>();
doAnswer(invocation -> {
handlerRef.set(invocation.getArgument(1));
return mock(ProtonDelivery.class);
}).when(sender).send(any(Message.class), any(Handler.class));
// WHEN trying to send a message
final Future<ProtonDelivery> result = messageSender.send("device", "some payload", "application/text", "token");
// which gets rejected by the peer
ProtonDelivery rejected = mock(ProtonDelivery.class);
when(rejected.remotelySettled()).thenReturn(Boolean.TRUE);
when(rejected.getRemoteState()).thenReturn(new Rejected());
handlerRef.get().handle(rejected);
// THEN the resulting future is succeeded nevertheless
assertTrue(result.succeeded());
// and the message has been sent
verify(sender).send(any(Message.class), eq(handlerRef.get()));
}
use of org.apache.qpid.proton.amqp.messaging.Rejected 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.Rejected in project azure-service-bus-java by Azure.
the class CoreMessageReceiver method deadLetterMessageAsync.
public CompletableFuture<Void> deadLetterMessageAsync(byte[] deliveryTag, String deadLetterReason, String deadLetterErrorDescription, Map<String, Object> propertiesToModify) {
Rejected outcome = new Rejected();
ErrorCondition error = new ErrorCondition(ClientConstants.DEADLETTERNAME, null);
Map<String, Object> errorInfo = new HashMap<String, Object>();
if (!StringUtil.isNullOrEmpty(deadLetterReason)) {
errorInfo.put(ClientConstants.DEADLETTER_REASON_HEADER, deadLetterReason);
}
if (!StringUtil.isNullOrEmpty(deadLetterErrorDescription)) {
errorInfo.put(ClientConstants.DEADLETTER_ERROR_DESCRIPTION_HEADER, deadLetterErrorDescription);
}
if (propertiesToModify != null) {
errorInfo.putAll(propertiesToModify);
}
error.setInfo(errorInfo);
outcome.setError(error);
return this.updateMessageStateAsync(deliveryTag, outcome);
}
use of org.apache.qpid.proton.amqp.messaging.Rejected in project activemq-artemis by apache.
the class AMQPSessionCallback method rejectMessage.
private void rejectMessage(Delivery delivery, Symbol errorCondition, String errorMessage) {
ErrorCondition condition = new ErrorCondition();
condition.setCondition(errorCondition);
condition.setDescription(errorMessage);
Rejected rejected = new Rejected();
rejected.setError(condition);
afterIO(new IOCallback() {
@Override
public void done() {
connection.lock();
try {
delivery.disposition(rejected);
delivery.settle();
} finally {
connection.unlock();
}
connection.flush();
}
@Override
public void onError(int errorCode, String errorMessage) {
}
});
}
use of org.apache.qpid.proton.amqp.messaging.Rejected in project activemq-artemis by apache.
the class ProtonServerReceiverContext method onMessage.
/*
* called when Proton receives a message to be delivered via a Delivery.
*
* This may be called more than once per deliver so we have to cache the buffer until we have received it all.
*
* */
@Override
public void onMessage(Delivery delivery) throws ActiveMQAMQPException {
Receiver receiver;
try {
if (!delivery.isReadable()) {
return;
}
if (delivery.isPartial()) {
return;
}
receiver = ((Receiver) delivery.getLink());
Transaction tx = null;
byte[] data;
data = new byte[delivery.available()];
receiver.recv(data, 0, data.length);
receiver.advance();
if (delivery.getRemoteState() instanceof TransactionalState) {
TransactionalState txState = (TransactionalState) delivery.getRemoteState();
tx = this.sessionSPI.getTransaction(txState.getTxnId(), false);
}
sessionSPI.serverSend(this, tx, receiver, delivery, address, delivery.getMessageFormat(), data);
flow(amqpCredits, minCreditRefresh);
} catch (Exception e) {
log.warn(e.getMessage(), e);
Rejected rejected = new Rejected();
ErrorCondition condition = new ErrorCondition();
if (e instanceof ActiveMQSecurityException) {
condition.setCondition(AmqpError.UNAUTHORIZED_ACCESS);
} else {
condition.setCondition(Symbol.valueOf("failed"));
}
condition.setDescription(e.getMessage());
rejected.setError(condition);
connection.lock();
try {
delivery.disposition(rejected);
delivery.settle();
} finally {
connection.unlock();
}
}
}
Aggregations