Search in sources :

Example 26 with Rejected

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

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

the class AbstractRequestResponseClientTest method testCreateAndSendRequestFailsOnRejectedMessage.

/**
 * Verifies that the client fails the result handler if the peer rejects
 * the request message.
 *
 * @param ctx The vert.x test context.
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
@Test
public void testCreateAndSendRequestFailsOnRejectedMessage(final TestContext ctx) {
    // GIVEN a request-response client that times out requests after 200 ms
    client.setRequestTimeout(200);
    // WHEN sending a request message with some headers and payload
    final Async sendFailure = ctx.async();
    final JsonObject payload = new JsonObject().put("key", "value");
    client.createAndSendRequest("get", null, payload, ctx.asyncAssertFailure(t -> {
        sendFailure.complete();
    }));
    // and the peer rejects the message
    final Rejected rejected = new Rejected();
    rejected.setError(ProtonHelper.condition("bad-request", "request message is malformed"));
    final ProtonDelivery delivery = mock(ProtonDelivery.class);
    when(delivery.getRemoteState()).thenReturn(rejected);
    final ArgumentCaptor<Handler> dispositionHandlerCaptor = ArgumentCaptor.forClass(Handler.class);
    verify(sender).send(any(Message.class), dispositionHandlerCaptor.capture());
    dispositionHandlerCaptor.getValue().handle(delivery);
    // THEN the result handler is failed
    sendFailure.await();
}
Also used : ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) HttpURLConnection(java.net.HttpURLConnection) CacheDirective(org.eclipse.hono.util.CacheDirective) TestContext(io.vertx.ext.unit.TestContext) ProtonReceiver(io.vertx.proton.ProtonReceiver) CoreMatchers(org.hamcrest.CoreMatchers) Async(io.vertx.ext.unit.Async) ArgumentMatchers.anyLong(org.mockito.ArgumentMatchers.anyLong) ProtonDelivery(io.vertx.proton.ProtonDelivery) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) ArgumentMatchers.eq(org.mockito.ArgumentMatchers.eq) RunWith(org.junit.runner.RunWith) ExpiringValueCache(org.eclipse.hono.cache.ExpiringValueCache) Context(io.vertx.core.Context) Assert.assertThat(org.junit.Assert.assertThat) ArgumentCaptor(org.mockito.ArgumentCaptor) AmqpValue(org.apache.qpid.proton.amqp.messaging.AmqpValue) Target(org.apache.qpid.proton.amqp.transport.Target) Duration(java.time.Duration) Map(java.util.Map) Timeout(org.junit.rules.Timeout) Message(org.apache.qpid.proton.message.Message) JsonObject(io.vertx.core.json.JsonObject) ClientConfigProperties(org.eclipse.hono.config.ClientConfigProperties) RequestResponseClientConfigProperties(org.eclipse.hono.client.RequestResponseClientConfigProperties) Before(org.junit.Before) Vertx(io.vertx.core.Vertx) ServerErrorException(org.eclipse.hono.client.ServerErrorException) Test(org.junit.Test) ProtonHelper(io.vertx.proton.ProtonHelper) VertxUnitRunner(io.vertx.ext.unit.junit.VertxUnitRunner) MessageHelper(org.eclipse.hono.util.MessageHelper) Mockito(org.mockito.Mockito) Rule(org.junit.Rule) ProtonSender(io.vertx.proton.ProtonSender) Handler(io.vertx.core.Handler) Collections(java.util.Collections) ProtonDelivery(io.vertx.proton.ProtonDelivery) Message(org.apache.qpid.proton.message.Message) Async(io.vertx.ext.unit.Async) JsonObject(io.vertx.core.json.JsonObject) Handler(io.vertx.core.Handler) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) Test(org.junit.Test)

Example 28 with Rejected

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

the class EventSenderImplTest method testSendMessageFailsForRejectedOutcome.

/**
 * Verifies that the sender fails if the peer does not accept a message.
 *
 * @param ctx The vert.x test context.
 */
@SuppressWarnings({ "unchecked" })
@Test
public void testSendMessageFailsForRejectedOutcome(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());
    // and the result fails once the peer rejects the message
    ProtonDelivery rejected = mock(ProtonDelivery.class);
    when(rejected.remotelySettled()).thenReturn(Boolean.TRUE);
    when(rejected.getRemoteState()).thenReturn(new Rejected());
    handlerRef.get().handle(rejected);
    assertFalse(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) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) Test(org.junit.Test)

Example 29 with Rejected

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

the class MessageForwardingEndpointTest method testProcessMessageRejectsRegistrationAssertionForWrongTenant.

/**
 * Verifies that a message containing a registration assertion for a tenant
 * other than the one from the message's target address is rejected.
 */
@Test
public void testProcessMessageRejectsRegistrationAssertionForWrongTenant() {
    final String invalidToken = getToken(SECRET, "wrong-tenant", "4711");
    final UpstreamReceiver client = mock(UpstreamReceiver.class);
    final ProtonDelivery delivery = mock(ProtonDelivery.class);
    when(tokenValidator.isValid(invalidToken, "tenant", "4711")).thenReturn(Boolean.FALSE);
    final MessageForwardingEndpoint<HonoMessagingConfigProperties> endpoint = getEndpoint();
    endpoint.setRegistrationAssertionValidator(tokenValidator);
    final Message msg = ProtonHelper.message();
    MessageHelper.addRegistrationAssertion(msg, invalidToken);
    MessageHelper.addAnnotation(msg, MessageHelper.APP_PROPERTY_RESOURCE, "telemetry/tenant/4711");
    endpoint.forwardMessage(client, delivery, msg);
    verify(delivery).disposition(any(Rejected.class), anyBoolean());
    verify(client, never()).close(any(ErrorCondition.class));
}
Also used : ProtonDelivery(io.vertx.proton.ProtonDelivery) Message(org.apache.qpid.proton.message.Message) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) Test(org.junit.Test)

Example 30 with Rejected

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

the class RequestResponseEndpointTest method testHandleMessageRejectsMalformedMessage.

/**
 * Verifies that the endpoint rejects malformed request messages.
 */
@Test
public void testHandleMessageRejectsMalformedMessage() {
    Message msg = ProtonHelper.message();
    ProtonConnection con = mock(ProtonConnection.class);
    ProtonDelivery delivery = mock(ProtonDelivery.class);
    RequestResponseEndpoint<ServiceConfigProperties> endpoint = getEndpoint(false);
    // WHEN a malformed message is received
    endpoint.handleMessage(con, receiver, resource, delivery, msg);
    // THEN the link is closed and the message is rejected
    ArgumentCaptor<DeliveryState> deliveryState = ArgumentCaptor.forClass(DeliveryState.class);
    verify(delivery).disposition(deliveryState.capture(), booleanThat(is(Boolean.TRUE)));
    assertThat(deliveryState.getValue(), instanceOf(Rejected.class));
    verify(receiver, never()).close();
}
Also used : ProtonConnection(io.vertx.proton.ProtonConnection) EventBusMessage(org.eclipse.hono.util.EventBusMessage) Message(org.apache.qpid.proton.message.Message) ProtonDelivery(io.vertx.proton.ProtonDelivery) DeliveryState(org.apache.qpid.proton.amqp.transport.DeliveryState) ServiceConfigProperties(org.eclipse.hono.config.ServiceConfigProperties) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) Test(org.junit.Test)

Aggregations

Rejected (org.apache.qpid.proton.amqp.messaging.Rejected)59 Message (org.apache.qpid.proton.message.Message)32 ProtonDelivery (io.vertx.proton.ProtonDelivery)28 Handler (io.vertx.core.Handler)27 DeliveryState (org.apache.qpid.proton.amqp.transport.DeliveryState)23 ErrorCondition (org.apache.qpid.proton.amqp.transport.ErrorCondition)23 Accepted (org.apache.qpid.proton.amqp.messaging.Accepted)21 Span (io.opentracing.Span)19 Test (org.junit.jupiter.api.Test)19 ProtonHelper (io.vertx.proton.ProtonHelper)18 ProtonSender (io.vertx.proton.ProtonSender)18 Released (org.apache.qpid.proton.amqp.messaging.Released)18 Future (io.vertx.core.Future)17 HttpURLConnection (java.net.HttpURLConnection)17 MessageHelper (org.eclipse.hono.util.MessageHelper)17 ProtonQoS (io.vertx.proton.ProtonQoS)16 ClientErrorException (org.eclipse.hono.client.ClientErrorException)16 ProtonReceiver (io.vertx.proton.ProtonReceiver)15 ArgumentMatchers.anyString (org.mockito.ArgumentMatchers.anyString)15 Truth.assertThat (com.google.common.truth.Truth.assertThat)14