Search in sources :

Example 1 with ProtonConnection

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

the class MessageForwardingEndpointTest method testOnLinkAttachClosesLinkIfDownstreamIsNotAvailable.

/**
 * Verifies that the endpoint does not open a link with a client if the
 * downstream messaging network is not available.
 */
@SuppressWarnings({ "unchecked" })
@Test
public void testOnLinkAttachClosesLinkIfDownstreamIsNotAvailable() {
    // GIVEN an endpoint without a connection to the downstream messaging network
    final ResourceIdentifier targetAddress = ResourceIdentifier.fromString("telemetry/tenant");
    final ProtonConnection connection = mock(ProtonConnection.class);
    final ProtonReceiver receiver = mock(ProtonReceiver.class);
    when(receiver.getRemoteQoS()).thenReturn(ProtonQoS.AT_MOST_ONCE);
    final DownstreamAdapter adapter = mock(DownstreamAdapter.class);
    doAnswer(invocation -> {
        final Handler<AsyncResult<Void>> handler = invocation.getArgument(1);
        handler.handle(Future.failedFuture("downstream not available"));
        return null;
    }).when(adapter).onClientAttach(any(UpstreamReceiver.class), any(Handler.class));
    final MessageForwardingEndpoint<HonoMessagingConfigProperties> endpoint = getEndpoint();
    endpoint.setDownstreamAdapter(adapter);
    // WHEN a client tries to attach
    endpoint.onLinkAttach(connection, receiver, targetAddress);
    // THEN the endpoint closes the link
    final ArgumentCaptor<ErrorCondition> errorCondition = ArgumentCaptor.forClass(ErrorCondition.class);
    verify(receiver).setCondition(errorCondition.capture());
    assertThat(errorCondition.getValue().getCondition(), is(AmqpError.PRECONDITION_FAILED));
    verify(receiver).close();
}
Also used : ProtonReceiver(io.vertx.proton.ProtonReceiver) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) ProtonConnection(io.vertx.proton.ProtonConnection) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) Handler(io.vertx.core.Handler) AsyncResult(io.vertx.core.AsyncResult) Test(org.junit.Test)

Example 2 with ProtonConnection

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

the class MessageForwardingEndpointTest method testOnLinkAttachClosesLinkIfClientWantsToUseUnsupportedDeliveryMode.

/**
 * Verifies that the endpoint does not open a link with a client that uses an unsupported
 * delivery mode.
 */
@Test
public void testOnLinkAttachClosesLinkIfClientWantsToUseUnsupportedDeliveryMode() {
    // GIVEN an endpoint
    MessageForwardingEndpoint<HonoMessagingConfigProperties> endpoint = getEndpoint();
    // WHEN a client tries to attach using an unsupported delivery mode
    final ProtonConnection connection = mock(ProtonConnection.class);
    final ProtonReceiver receiver = mock(ProtonReceiver.class);
    final ResourceIdentifier targetAddress = ResourceIdentifier.fromString("telemetry/tenant");
    when(receiver.getRemoteQoS()).thenReturn(ProtonQoS.AT_LEAST_ONCE);
    endpoint.onLinkAttach(connection, receiver, targetAddress);
    // THEN the endpoint closes the link
    final ArgumentCaptor<ErrorCondition> errorCondition = ArgumentCaptor.forClass(ErrorCondition.class);
    verify(receiver).setCondition(errorCondition.capture());
    assertThat(errorCondition.getValue(), is(ErrorConditions.ERROR_UNSUPPORTED_DELIVERY_MODE));
    verify(receiver).close();
}
Also used : ProtonReceiver(io.vertx.proton.ProtonReceiver) ProtonConnection(io.vertx.proton.ProtonConnection) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) Test(org.junit.Test)

Example 3 with ProtonConnection

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

the class MessageForwardingEndpointTest method testMessageHandlerRejectsMalformedMessage.

/**
 * Verifies that the endpoint rejects messages that do not pass formal verification.
 */
@SuppressWarnings({ "unchecked" })
@Test
public void testMessageHandlerRejectsMalformedMessage() {
    // GIVEN an endpoint with an attached client
    final ResourceIdentifier targetAddress = ResourceIdentifier.fromString("telemetry/tenant");
    final ProtonConnection connection = mock(ProtonConnection.class);
    when(connection.getRemoteContainer()).thenReturn("test-client");
    final ProtonReceiver receiver = mock(ProtonReceiver.class);
    when(receiver.getRemoteQoS()).thenReturn(ProtonQoS.AT_MOST_ONCE);
    final DownstreamAdapter adapter = mock(DownstreamAdapter.class);
    doAnswer(invocation -> {
        final Handler<AsyncResult<Void>> resultHandler = invocation.getArgument(1);
        resultHandler.handle(Future.succeededFuture());
        return null;
    }).when(adapter).onClientAttach(any(UpstreamReceiver.class), any(Handler.class));
    final MessageForwardingEndpoint<HonoMessagingConfigProperties> endpoint = getEndpoint(false);
    endpoint.setDownstreamAdapter(adapter);
    endpoint.onLinkAttach(connection, receiver, targetAddress);
    final ArgumentCaptor<ProtonMessageHandler> messageHandler = ArgumentCaptor.forClass(ProtonMessageHandler.class);
    verify(receiver).handler(messageHandler.capture());
    // WHEN a client sends a malformed message
    final Message message = ProtonHelper.message("malformed");
    final ProtonDelivery upstreamDelivery = mock(ProtonDelivery.class);
    messageHandler.getValue().handle(upstreamDelivery, message);
    // THEN the endpoint rejects the message
    final ArgumentCaptor<Rejected> deliveryState = ArgumentCaptor.forClass(Rejected.class);
    verify(upstreamDelivery).disposition(deliveryState.capture(), eq(Boolean.TRUE));
    assertThat(deliveryState.getValue().getError().getCondition(), is(AmqpError.DECODE_ERROR));
    // but does not close the link
    verify(receiver, never()).close();
    // and the message is not forwarded to the downstream adapter
    verify(adapter, never()).processMessage(any(UpstreamReceiver.class), eq(upstreamDelivery), eq(message));
}
Also used : ProtonReceiver(io.vertx.proton.ProtonReceiver) Message(org.apache.qpid.proton.message.Message) ProtonDelivery(io.vertx.proton.ProtonDelivery) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) Handler(io.vertx.core.Handler) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) AsyncResult(io.vertx.core.AsyncResult) Test(org.junit.Test)

Example 4 with ProtonConnection

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

the class TestSupport method openConnection.

public static ProtonConnection openConnection(final TestContext ctx, final Vertx vertx, final String host, final int port) {
    final Async connected = ctx.async();
    final AtomicReference<ProtonConnection> protonConnection = new AtomicReference<>();
    final ProtonClient client = ProtonClient.create(vertx);
    client.connect(host, port, ar -> {
        if (ar.succeeded()) {
            protonConnection.set(ar.result());
            protonConnection.get().setContainer(CLIENT_CONTAINER).open();
            connected.complete();
        } else {
            ctx.fail(ar.cause());
        }
    });
    connected.awaitSuccess(2000);
    return protonConnection.get();
}
Also used : ProtonConnection(io.vertx.proton.ProtonConnection) Async(io.vertx.ext.unit.Async) AtomicReference(java.util.concurrent.atomic.AtomicReference) ProtonClient(io.vertx.proton.ProtonClient)

Example 5 with ProtonConnection

use of io.vertx.proton.ProtonConnection 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)

Aggregations

ProtonConnection (io.vertx.proton.ProtonConnection)63 ProtonClient (io.vertx.proton.ProtonClient)37 Message (org.apache.qpid.proton.message.Message)36 Handler (io.vertx.core.Handler)35 Test (org.junit.Test)33 Async (io.vertx.ext.unit.Async)27 ProtonServer (io.vertx.proton.ProtonServer)25 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)25 AmqpValue (org.apache.qpid.proton.amqp.messaging.AmqpValue)25 AsyncResult (io.vertx.core.AsyncResult)24 TestContext (io.vertx.ext.unit.TestContext)24 VertxUnitRunner (io.vertx.ext.unit.junit.VertxUnitRunner)24 RunWith (org.junit.runner.RunWith)24 Section (org.apache.qpid.proton.amqp.messaging.Section)23 ProtonHelper.message (io.vertx.proton.ProtonHelper.message)21 Rejected (org.apache.qpid.proton.amqp.messaging.Rejected)21 ProtonStreams (io.vertx.proton.streams.ProtonStreams)20 Vertx (io.vertx.core.Vertx)19 Symbol (org.apache.qpid.proton.amqp.Symbol)19 Accepted (org.apache.qpid.proton.amqp.messaging.Accepted)19