Search in sources :

Example 6 with ProtonSender

use of io.vertx.proton.ProtonSender 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 7 with ProtonSender

use of io.vertx.proton.ProtonSender in project hono by eclipse.

the class ForwardingDownstreamAdapterTest method testDownstreamLinkHandlerClosesUpstreamReceiver.

@SuppressWarnings({ "unchecked", "rawtypes" })
private void testDownstreamLinkHandlerClosesUpstreamReceiver(final BiConsumer<ProtonSender, ArgumentCaptor<Handler>> handlerCaptor) {
    final UpstreamReceiver client = newClient();
    final ProtonSender downstreamSender = newMockSender(false);
    when(downstreamSender.isOpen()).thenReturn(Boolean.FALSE);
    final HandlerCapturingConnectionFactory factory = new HandlerCapturingConnectionFactory(con);
    // GIVEN an adapter connected to a downstream container
    givenADownstreamAdapter(downstreamSender);
    adapter.setDownstreamConnectionFactory(factory);
    adapter.start(Future.future());
    adapter.onClientAttach(client, s -> {
    });
    final ArgumentCaptor<Handler> captor = ArgumentCaptor.forClass(Handler.class);
    handlerCaptor.accept(downstreamSender, captor);
    // WHEN the downstream container detaches the sender link
    captor.getValue().handle(Future.succeededFuture(downstreamSender));
    // THEN the upstream client is closed
    verify(client).close(any());
    // and the sender is removed from the list of active senders
    assertTrue(adapter.isActiveSendersEmpty());
}
Also used : ProtonSender(io.vertx.proton.ProtonSender) Handler(io.vertx.core.Handler)

Example 8 with ProtonSender

use of io.vertx.proton.ProtonSender in project hono by eclipse.

the class RequestResponseEndpoint method onLinkAttach.

/**
 * Handles a client's request to establish a link for receiving responses
 * to service invocations.
 * <p>
 * This method registers a consumer on the vert.x event bus for the given reply-to address.
 * Response messages received over the event bus are transformed into AMQP messages using
 * the {@link #getAmqpReply(EventBusMessage)} method and sent to the client over the established
 * link.
 *
 * @param con The AMQP connection that the link is part of.
 * @param sender The link to establish.
 * @param replyToAddress The reply-to address to create a consumer on the event bus for.
 */
@Override
public final void onLinkAttach(final ProtonConnection con, final ProtonSender sender, final ResourceIdentifier replyToAddress) {
    if (isValidReplyToAddress(replyToAddress)) {
        logger.debug("establishing sender link with client [{}]", sender.getName());
        final MessageConsumer<JsonObject> replyConsumer = vertx.eventBus().consumer(replyToAddress.toString(), message -> {
            // TODO check for correct session here...?
            if (logger.isTraceEnabled()) {
                logger.trace("forwarding reply to client [{}]: {}", sender.getName(), message.body().encodePrettily());
            }
            final EventBusMessage response = EventBusMessage.fromJson(message.body());
            filterResponse(Constants.getClientPrincipal(con), response).recover(t -> {
                final int status = Optional.of(t).map(cause -> {
                    if (cause instanceof ServiceInvocationException) {
                        return ((ServiceInvocationException) cause).getErrorCode();
                    } else {
                        return null;
                    }
                }).orElse(HttpURLConnection.HTTP_INTERNAL_ERROR);
                return Future.succeededFuture(response.getResponse(status));
            }).map(filteredResponse -> {
                final Message amqpReply = getAmqpReply(filteredResponse);
                sender.send(amqpReply);
                return null;
            });
        });
        sender.setQoS(ProtonQoS.AT_LEAST_ONCE);
        sender.closeHandler(senderClosed -> {
            logger.debug("client [{}] closed sender link, removing associated event bus consumer [{}]", sender.getName(), replyConsumer.address());
            replyConsumer.unregister();
            if (senderClosed.succeeded()) {
                senderClosed.result().close();
            }
        });
        sender.open();
    } else {
        logger.debug("client [{}] provided invalid reply-to address", sender.getName());
        sender.setCondition(ProtonHelper.condition(AmqpError.INVALID_FIELD, String.format("reply-to address must have the following format %s/<tenant>/<reply-address>", getName())));
        sender.close();
    }
}
Also used : HttpURLConnection(java.net.HttpURLConnection) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonReceiver(io.vertx.proton.ProtonReceiver) AmqpErrorException(org.eclipse.hono.util.AmqpErrorException) ProtonDelivery(io.vertx.proton.ProtonDelivery) DecodeException(io.vertx.core.json.DecodeException) Autowired(org.springframework.beans.factory.annotation.Autowired) EventBusMessage(org.eclipse.hono.util.EventBusMessage) HonoUser(org.eclipse.hono.auth.HonoUser) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) ServiceConfigProperties(org.eclipse.hono.config.ServiceConfigProperties) Constants(org.eclipse.hono.util.Constants) Message(org.apache.qpid.proton.message.Message) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) JsonObject(io.vertx.core.json.JsonObject) AmqpError(org.apache.qpid.proton.amqp.transport.AmqpError) Vertx(io.vertx.core.Vertx) ProtonHelper(io.vertx.proton.ProtonHelper) ProtonQoS(io.vertx.proton.ProtonQoS) MessageHelper(org.eclipse.hono.util.MessageHelper) Future(io.vertx.core.Future) Objects(java.util.Objects) Optional(java.util.Optional) ProtonSender(io.vertx.proton.ProtonSender) ClaimsBasedAuthorizationService(org.eclipse.hono.service.auth.ClaimsBasedAuthorizationService) MessageConsumer(io.vertx.core.eventbus.MessageConsumer) AuthorizationService(org.eclipse.hono.service.auth.AuthorizationService) EventBusMessage(org.eclipse.hono.util.EventBusMessage) Message(org.apache.qpid.proton.message.Message) EventBusMessage(org.eclipse.hono.util.EventBusMessage) JsonObject(io.vertx.core.json.JsonObject) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException)

Example 9 with ProtonSender

use of io.vertx.proton.ProtonSender in project hono by eclipse.

the class AbstractHonoClientTest method testCreateSenderFails.

@SuppressWarnings({ "unchecked", "rawtypes" })
private void testCreateSenderFails(final Supplier<ErrorCondition> errorSupplier, final Predicate<Throwable> failureAssertion) {
    final Record attachments = new RecordImpl();
    final ProtonSender sender = mock(ProtonSender.class);
    when(sender.getRemoteCondition()).thenReturn(errorSupplier.get());
    when(sender.attachments()).thenReturn(attachments);
    final ProtonConnection con = mock(ProtonConnection.class);
    when(con.createSender(anyString())).thenReturn(sender);
    final Future<ProtonSender> result = AbstractHonoClient.createSender(context, props, con, "target", ProtonQoS.AT_LEAST_ONCE, null);
    final ArgumentCaptor<Handler> openHandler = ArgumentCaptor.forClass(Handler.class);
    verify(sender).openHandler(openHandler.capture());
    openHandler.getValue().handle(Future.failedFuture(new IllegalStateException()));
    assertTrue(result.failed());
    assertTrue(failureAssertion.test(result.cause()));
}
Also used : ProtonSender(io.vertx.proton.ProtonSender) ProtonConnection(io.vertx.proton.ProtonConnection) Handler(io.vertx.core.Handler) Record(org.apache.qpid.proton.engine.Record) RecordImpl(org.apache.qpid.proton.engine.impl.RecordImpl)

Example 10 with ProtonSender

use of io.vertx.proton.ProtonSender in project hono by eclipse.

the class HonoClientUnitTestHelper method mockProtonSender.

/**
 * Creates a mocked Proton sender which always returns {@code true} when its isOpen method is called.
 *
 * @return The mocked sender.
 */
public static final ProtonSender mockProtonSender() {
    final ProtonSender sender = mock(ProtonSender.class);
    when(sender.isOpen()).thenReturn(Boolean.TRUE);
    return sender;
}
Also used : ProtonSender(io.vertx.proton.ProtonSender)

Aggregations

ProtonSender (io.vertx.proton.ProtonSender)22 Handler (io.vertx.core.Handler)11 Message (org.apache.qpid.proton.message.Message)9 Test (org.junit.Test)9 ProtonDelivery (io.vertx.proton.ProtonDelivery)8 ProtonConnection (io.vertx.proton.ProtonConnection)6 MessagingMetrics (org.eclipse.hono.messaging.MessagingMetrics)5 UpstreamReceiver (org.eclipse.hono.messaging.UpstreamReceiver)5 Vertx (io.vertx.core.Vertx)4 Future (io.vertx.core.Future)3 Async (io.vertx.ext.unit.Async)3 ProtonQoS (io.vertx.proton.ProtonQoS)3 ErrorCondition (org.apache.qpid.proton.amqp.transport.ErrorCondition)3 Record (org.apache.qpid.proton.engine.Record)3 Constants (org.eclipse.hono.util.Constants)3 ResourceIdentifier (org.eclipse.hono.util.ResourceIdentifier)3 AsyncResult (io.vertx.core.AsyncResult)2 ProtonClientOptions (io.vertx.proton.ProtonClientOptions)2 ProtonHelper (io.vertx.proton.ProtonHelper)2 ProtonSession (io.vertx.proton.ProtonSession)2