Search in sources :

Example 1 with Accepted

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

the class ForwardingEventDownstreamAdapterTest method testProcessMessageForwardsMessageToDownstreamSender.

/**
 * Verifies that an event uploaded by an upstream client is forwarded to the
 * downstream container.
 *
 * @param ctx The test context.
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
@Test
public void testProcessMessageForwardsMessageToDownstreamSender(final TestContext ctx) {
    final UpstreamReceiver client = newClient();
    final ProtonDelivery delivery = mock(ProtonDelivery.class);
    final ProtonDelivery downstreamDelivery = mock(ProtonDelivery.class);
    when(downstreamDelivery.getRemoteState()).thenReturn(ACCEPTED);
    when(downstreamDelivery.remotelySettled()).thenReturn(true);
    // GIVEN an adapter with a connection to a downstream container
    final Async msgSent = ctx.async();
    ProtonSender sender = newMockSender(false);
    when(sender.send(any(Message.class), any(Handler.class))).then(invocation -> {
        msgSent.complete();
        final Handler handler = invocation.getArgument(1);
        handler.handle(downstreamDelivery);
        return null;
    });
    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 has been delivered to the downstream container
    msgSent.await(1000);
    // and disposition was returned
    verify(delivery).disposition(any(Accepted.class), eq(Boolean.TRUE));
}
Also used : ProtonSender(io.vertx.proton.ProtonSender) ProtonDelivery(io.vertx.proton.ProtonDelivery) Message(org.apache.qpid.proton.message.Message) Async(io.vertx.ext.unit.Async) Handler(io.vertx.core.Handler) UpstreamReceiver(org.eclipse.hono.messaging.UpstreamReceiver) MessagingMetrics(org.eclipse.hono.messaging.MessagingMetrics) Accepted(org.apache.qpid.proton.amqp.messaging.Accepted) Test(org.junit.Test)

Example 2 with Accepted

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

the class AbstractRequestResponseClient method sendRequest.

/**
 * Sends a request message via this client's sender link to the peer.
 * <p>
 * This method first checks if the sender has any credit left. If not, the result handler is failed immediately.
 * Otherwise, the request message is sent and a timer is started which fails the result handler,
 * if no response is received within <em>requestTimeoutMillis</em> milliseconds.
 *
 * @param request The message to send.
 * @param resultHandler The handler to notify about the outcome of the request.
 * @param cacheKey The key to use for caching the response (if the service allows caching).
 */
private final void sendRequest(final Message request, final Handler<AsyncResult<R>> resultHandler, final Object cacheKey) {
    context.runOnContext(req -> {
        if (sender.sendQueueFull()) {
            LOG.debug("cannot send request to peer, no credit left for link [target: {}]", targetAddress);
            resultHandler.handle(Future.failedFuture(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "no credit available for sending request")));
        } else {
            final Object correlationId = Optional.ofNullable(request.getCorrelationId()).orElse(request.getMessageId());
            final TriTuple<Handler<AsyncResult<R>>, Object, Object> handler = TriTuple.of(resultHandler, cacheKey, null);
            replyMap.put(correlationId, handler);
            sender.send(request, deliveryUpdated -> {
                if (Rejected.class.isInstance(deliveryUpdated.getRemoteState())) {
                    final Rejected rejected = (Rejected) deliveryUpdated.getRemoteState();
                    if (rejected.getError() != null) {
                        LOG.debug("service did not accept request [target address: {}, subject: {}, correlation ID: {}]: {}", targetAddress, request.getSubject(), correlationId, rejected.getError());
                        cancelRequest(correlationId, Future.failedFuture(StatusCodeMapper.from(rejected.getError())));
                    } else {
                        LOG.debug("service did not accept request [target address: {}, subject: {}, correlation ID: {}]", targetAddress, request.getSubject(), correlationId);
                        cancelRequest(correlationId, Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST)));
                    }
                } else if (Accepted.class.isInstance(deliveryUpdated.getRemoteState())) {
                    LOG.trace("service has accepted request [target address: {}, subject: {}, correlation ID: {}]", targetAddress, request.getSubject(), correlationId);
                } else {
                    LOG.debug("service did not accept request [target address: {}, subject: {}, correlation ID: {}]: {}", targetAddress, request.getSubject(), correlationId, deliveryUpdated.getRemoteState());
                    cancelRequest(correlationId, Future.failedFuture(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE)));
                }
            });
            if (requestTimeoutMillis > 0) {
                context.owner().setTimer(requestTimeoutMillis, tid -> {
                    cancelRequest(correlationId, Future.failedFuture(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "request timed out after " + requestTimeoutMillis + "ms")));
                });
            }
            if (LOG.isDebugEnabled()) {
                final String deviceId = MessageHelper.getDeviceId(request);
                if (deviceId == null) {
                    LOG.debug("sent request [target address: {}, subject: {}, correlation ID: {}] to service", targetAddress, request.getSubject(), correlationId);
                } else {
                    LOG.debug("sent request [target address: {}, subject: {}, correlation ID: {}, device ID: {}] to service", targetAddress, request.getSubject(), correlationId, deviceId);
                }
            }
        }
    });
}
Also used : Handler(io.vertx.core.Handler) ClientErrorException(org.eclipse.hono.client.ClientErrorException) JsonObject(io.vertx.core.json.JsonObject) ServerErrorException(org.eclipse.hono.client.ServerErrorException) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) Accepted(org.apache.qpid.proton.amqp.messaging.Accepted)

Example 3 with Accepted

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

the class EventSenderImplTest method testSendMessageWaitsForAcceptedOutcome.

/**
 * Verifies that the sender waits for the peer to settle and
 * accept a message before succeeding the returned future.
 *
 * @param ctx The vert.x test context.
 */
@SuppressWarnings({ "unchecked" })
@Test
public void testSendMessageWaitsForAcceptedOutcome(final TestContext ctx) {
    // GIVEN a sender that has credit
    when(sender.sendQueueFull()).thenReturn(Boolean.FALSE);
    MessageSender messageSender = new EventSenderImpl(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");
    // THEN the message has been sent
    // and the result is not completed yet
    verify(sender).send(any(Message.class), eq(handlerRef.get()));
    assertFalse(result.isComplete());
    // until it gets accepted by the peer
    ProtonDelivery accepted = mock(ProtonDelivery.class);
    when(accepted.remotelySettled()).thenReturn(Boolean.TRUE);
    when(accepted.getRemoteState()).thenReturn(new Accepted());
    handlerRef.get().handle(accepted);
    assertTrue(result.succeeded());
}
Also used : Message(org.apache.qpid.proton.message.Message) ProtonDelivery(io.vertx.proton.ProtonDelivery) MessageSender(org.eclipse.hono.client.MessageSender) Handler(io.vertx.core.Handler) AtomicReference(java.util.concurrent.atomic.AtomicReference) Accepted(org.apache.qpid.proton.amqp.messaging.Accepted) Test(org.junit.Test)

Example 4 with Accepted

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

the class ForwardingTelemetryDownstreamAdapterTest method testProcessMessageForwardsMessageToDownstreamSender.

/**
 * Verifies that pre-settled telemetry data uploaded by an upstream client is
 * forwarded to the downstream container and is accepted and settled immediately.
 *
 * @param ctx The test context.
 */
@Test
public void testProcessMessageForwardsMessageToDownstreamSender(final TestContext ctx) {
    final UpstreamReceiver client = TestSupport.newClient();
    // GIVEN an adapter with a connection to a downstream container
    final ProtonSender sender = TestSupport.newMockSender(false);
    final ForwardingTelemetryDownstreamAdapter adapter = new ForwardingTelemetryDownstreamAdapter(vertx, TestSupport.newMockSenderFactory(sender));
    adapter.setMetrics(mock(MessagingMetrics.class));
    adapter.setDownstreamConnectionFactory(connectionFactory);
    adapter.start(Future.future());
    adapter.addSender(client, sender);
    // WHEN processing a pre-settled telemetry message
    final Message msg = ProtonHelper.message(TELEMETRY_MSG_CONTENT);
    MessageHelper.addDeviceId(msg, DEVICE_ID);
    final ProtonDelivery upstreamDelivery = mock(ProtonDelivery.class);
    when(upstreamDelivery.remotelySettled()).thenReturn(Boolean.TRUE);
    adapter.processMessage(client, upstreamDelivery, msg);
    // THEN the message is being delivered to the downstream container
    verify(sender).send(eq(msg));
    // and the upstream delivery is settled with the accepted outcome
    verify(upstreamDelivery).disposition(any(Accepted.class), eq(Boolean.TRUE));
}
Also used : ProtonSender(io.vertx.proton.ProtonSender) Message(org.apache.qpid.proton.message.Message) ProtonDelivery(io.vertx.proton.ProtonDelivery) UpstreamReceiver(org.eclipse.hono.messaging.UpstreamReceiver) MessagingMetrics(org.eclipse.hono.messaging.MessagingMetrics) Accepted(org.apache.qpid.proton.amqp.messaging.Accepted) Test(org.junit.Test)

Aggregations

Accepted (org.apache.qpid.proton.amqp.messaging.Accepted)4 Handler (io.vertx.core.Handler)3 ProtonDelivery (io.vertx.proton.ProtonDelivery)3 Message (org.apache.qpid.proton.message.Message)3 Test (org.junit.Test)3 ProtonSender (io.vertx.proton.ProtonSender)2 MessagingMetrics (org.eclipse.hono.messaging.MessagingMetrics)2 UpstreamReceiver (org.eclipse.hono.messaging.UpstreamReceiver)2 JsonObject (io.vertx.core.json.JsonObject)1 Async (io.vertx.ext.unit.Async)1 AtomicReference (java.util.concurrent.atomic.AtomicReference)1 Rejected (org.apache.qpid.proton.amqp.messaging.Rejected)1 ClientErrorException (org.eclipse.hono.client.ClientErrorException)1 MessageSender (org.eclipse.hono.client.MessageSender)1 ServerErrorException (org.eclipse.hono.client.ServerErrorException)1