Search in sources :

Example 1 with Released

use of org.apache.qpid.proton.amqp.messaging.Released in project hono by eclipse.

the class ForwardingEventDownstreamAdapterTest method testProcessMessageReleasesMessageIfNoCreditIsAvailable.

/**
 * Verifies that an event is released if no downstream credit is available.
 *
 * @param ctx The test context.
 */
@SuppressWarnings("unchecked")
@Test
public void testProcessMessageReleasesMessageIfNoCreditIsAvailable(final TestContext ctx) {
    final UpstreamReceiver client = newClient();
    final ProtonDelivery delivery = mock(ProtonDelivery.class);
    when(delivery.remotelySettled()).thenReturn(Boolean.FALSE);
    // GIVEN an adapter with a connection to a downstream container
    ProtonSender sender = newMockSender(false);
    when(sender.sendQueueFull()).thenReturn(true);
    ForwardingEventDownstreamAdapter adapter = new ForwardingEventDownstreamAdapter(vertx, newMockSenderFactory(sender));
    adapter.setMetrics(mock(MessagingMetrics.class));
    adapter.setDownstreamConnectionFactory(newMockConnectionFactory(false));
    adapter.start(Future.future());
    adapter.addSender(client, sender);
    // WHEN processing an event
    Message msg = ProtonHelper.message(EVENT_MSG_CONTENT);
    MessageHelper.addDeviceId(msg, DEVICE_ID);
    adapter.processMessage(client, delivery, msg);
    // THEN the message is released
    verify(delivery).disposition(any(Released.class), eq(Boolean.TRUE));
    // and not delivered to the downstream container
    verify(sender, never()).send(any(Message.class), any(Handler.class));
}
Also used : ProtonSender(io.vertx.proton.ProtonSender) Released(org.apache.qpid.proton.amqp.messaging.Released) ProtonDelivery(io.vertx.proton.ProtonDelivery) Message(org.apache.qpid.proton.message.Message) Handler(io.vertx.core.Handler) UpstreamReceiver(org.eclipse.hono.messaging.UpstreamReceiver) MessagingMetrics(org.eclipse.hono.messaging.MessagingMetrics) Test(org.junit.Test)

Example 2 with Released

use of org.apache.qpid.proton.amqp.messaging.Released in project hono by eclipse.

the class EventConsumerImplTest method testCreateRegistersBiConsumerAsMessageHandler.

/**
 * Verifies that the message delivery for a received event is forwarded to the
 * registered event consumer.
 *
 * @param ctx The test context.
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
@Test
public void testCreateRegistersBiConsumerAsMessageHandler(final TestContext ctx) {
    // GIVEN an event consumer that releases all messages
    final Async consumerCreation = ctx.async();
    final BiConsumer<ProtonDelivery, Message> eventConsumer = (delivery, message) -> {
        ProtonHelper.released(delivery, true);
    };
    final RecordImpl attachments = new RecordImpl();
    final Source source = mock(Source.class);
    when(source.toString()).thenReturn("event/tenant");
    final ProtonReceiver receiver = mock(ProtonReceiver.class);
    when(receiver.getSource()).thenReturn(source);
    when(receiver.attachments()).thenReturn(attachments);
    when(receiver.getRemoteQoS()).thenReturn(ProtonQoS.AT_LEAST_ONCE);
    when(receiver.open()).then(answer -> {
        consumerCreation.complete();
        return receiver;
    });
    final ProtonConnection con = mock(ProtonConnection.class);
    when(con.createReceiver(anyString())).thenReturn(receiver);
    when(receiver.openHandler(any(Handler.class))).thenAnswer(invocation -> {
        final Handler handler = invocation.getArgument(0);
        handler.handle(Future.succeededFuture(receiver));
        return receiver;
    });
    final ArgumentCaptor<ProtonMessageHandler> messageHandler = ArgumentCaptor.forClass(ProtonMessageHandler.class);
    EventConsumerImpl.create(vertx.getOrCreateContext(), new ClientConfigProperties(), con, "tenant", eventConsumer, open -> {
    }, remoteDetach -> {
    });
    consumerCreation.await();
    verify(receiver).handler(messageHandler.capture());
    // WHEN an event is received
    final ProtonDelivery delivery = mock(ProtonDelivery.class);
    final Message msg = mock(Message.class);
    messageHandler.getValue().handle(delivery, msg);
    // THEN the message is released and settled
    verify(delivery).disposition(any(Released.class), eq(Boolean.TRUE));
}
Also used : TestContext(io.vertx.ext.unit.TestContext) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonReceiver(io.vertx.proton.ProtonReceiver) Async(io.vertx.ext.unit.Async) ProtonDelivery(io.vertx.proton.ProtonDelivery) RunWith(org.junit.runner.RunWith) Timeout(io.vertx.ext.unit.junit.Timeout) ArgumentCaptor(org.mockito.ArgumentCaptor) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) RecordImpl(org.apache.qpid.proton.engine.impl.RecordImpl) After(org.junit.After) BiConsumer(java.util.function.BiConsumer) Message(org.apache.qpid.proton.message.Message) ClientConfigProperties(org.eclipse.hono.config.ClientConfigProperties) Before(org.junit.Before) Vertx(io.vertx.core.Vertx) Test(org.junit.Test) ProtonHelper(io.vertx.proton.ProtonHelper) ProtonQoS(io.vertx.proton.ProtonQoS) VertxUnitRunner(io.vertx.ext.unit.junit.VertxUnitRunner) Released(org.apache.qpid.proton.amqp.messaging.Released) Future(io.vertx.core.Future) Mockito(org.mockito.Mockito) Source(org.apache.qpid.proton.amqp.transport.Source) Rule(org.junit.Rule) Handler(io.vertx.core.Handler) ProtonReceiver(io.vertx.proton.ProtonReceiver) Released(org.apache.qpid.proton.amqp.messaging.Released) ProtonDelivery(io.vertx.proton.ProtonDelivery) Message(org.apache.qpid.proton.message.Message) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) Handler(io.vertx.core.Handler) RecordImpl(org.apache.qpid.proton.engine.impl.RecordImpl) Source(org.apache.qpid.proton.amqp.transport.Source) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) Async(io.vertx.ext.unit.Async) ClientConfigProperties(org.eclipse.hono.config.ClientConfigProperties) Test(org.junit.Test)

Example 3 with Released

use of org.apache.qpid.proton.amqp.messaging.Released 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 4 with Released

use of org.apache.qpid.proton.amqp.messaging.Released in project hono by eclipse.

the class ProtonBasedMappingAndDelegatingCommandHandlerTest method testMapWithCommandHandlerNotFound.

/**
 * Verifies the behaviour of the <em>mapAndDelegateIncomingCommandMessage</em> method in a scenario where
 * the command handler is not found.
 */
@Test
public void testMapWithCommandHandlerNotFound() {
    final String deviceId = "4711";
    // GIVEN a 'NOT_FOUND' error when looking up the adapter instance
    when(commandTargetMapper.getTargetGatewayAndAdapterInstance(anyString(), anyString(), any())).thenReturn(Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_NOT_FOUND)));
    // WHEN mapping and delegating a command message
    final Message message = getValidCommandMessage(deviceId);
    final ProtonDelivery delivery = mock(ProtonDelivery.class);
    mappingAndDelegatingCommandHandler.mapAndDelegateIncomingCommandMessage(tenantId, delivery, message);
    // THEN the disposition is RELEASED
    verify(delivery).disposition(any(Released.class), eq(true));
}
Also used : Released(org.apache.qpid.proton.amqp.messaging.Released) Message(org.apache.qpid.proton.message.Message) ProtonDelivery(io.vertx.proton.ProtonDelivery) ClientErrorException(org.eclipse.hono.client.ClientErrorException) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) Test(org.junit.jupiter.api.Test)

Example 5 with Released

use of org.apache.qpid.proton.amqp.messaging.Released in project hono by eclipse.

the class ProtonBasedMappingAndDelegatingCommandHandlerTest method testMapWithCommandHandlerOnAnotherInstanceWithMessageSendingFailed.

/**
 * Verifies the behaviour of the <em>mapAndDelegateIncomingCommandMessage</em> method in a scenario where
 * the command shall get handled by some adapter instance and where sending the command message to
 * the adapter instance fails.
 */
@Test
public void testMapWithCommandHandlerOnAnotherInstanceWithMessageSendingFailed() {
    final String deviceId = "4711";
    // GIVEN a deviceId commandHandler registered for some adapter instance
    final String someAdapterInstance = "someAdapterInstance";
    when(commandTargetMapper.getTargetGatewayAndAdapterInstance(anyString(), anyString(), any())).thenReturn(Future.succeededFuture(createTargetAdapterInstanceJson(deviceId, someAdapterInstance)));
    // AND an error when sending the command message to that adapter instance (no credit)
    when(sender.sendQueueFull()).thenReturn(Boolean.TRUE);
    // WHEN mapping and delegating the command message
    final Message message = getValidCommandMessage(deviceId);
    final ProtonDelivery delivery = mock(ProtonDelivery.class);
    mappingAndDelegatingCommandHandler.mapAndDelegateIncomingCommandMessage(tenantId, delivery, message);
    // THEN the delivery gets RELEASED
    verify(delivery).disposition(any(Released.class), eq(true));
}
Also used : Released(org.apache.qpid.proton.amqp.messaging.Released) Message(org.apache.qpid.proton.message.Message) ProtonDelivery(io.vertx.proton.ProtonDelivery) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) Test(org.junit.jupiter.api.Test)

Aggregations

Released (org.apache.qpid.proton.amqp.messaging.Released)14 Rejected (org.apache.qpid.proton.amqp.messaging.Rejected)9 DeliveryState (org.apache.qpid.proton.amqp.transport.DeliveryState)8 Message (org.apache.qpid.proton.message.Message)8 Accepted (org.apache.qpid.proton.amqp.messaging.Accepted)7 Modified (org.apache.qpid.proton.amqp.messaging.Modified)7 Handler (io.vertx.core.Handler)6 ProtonDelivery (io.vertx.proton.ProtonDelivery)6 AsyncResult (io.vertx.core.AsyncResult)4 ProtonConnection (io.vertx.proton.ProtonConnection)4 ErrorCondition (org.apache.qpid.proton.amqp.transport.ErrorCondition)4 ClientErrorException (org.eclipse.hono.client.ClientErrorException)4 Future (io.vertx.core.Future)3 Async (io.vertx.ext.unit.Async)3 TestContext (io.vertx.ext.unit.TestContext)3 VertxUnitRunner (io.vertx.ext.unit.junit.VertxUnitRunner)3 ProtonHelper (io.vertx.proton.ProtonHelper)3 ProtonQoS (io.vertx.proton.ProtonQoS)3 ProtonReceiver (io.vertx.proton.ProtonReceiver)3 ProtonSender (io.vertx.proton.ProtonSender)3