Search in sources :

Example 16 with ProtonSender

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

the class ForwardingDownstreamAdapter method onClientAttach.

@Override
public final void onClientAttach(final UpstreamReceiver client, final Handler<AsyncResult<Void>> resultHandler) {
    if (!running) {
        throw new IllegalStateException("adapter must be started first");
    }
    Objects.requireNonNull(client);
    Objects.requireNonNull(resultHandler);
    ProtonSender sender = activeSenders.get(client);
    if (sender != null && sender.isOpen()) {
        logger.info("reusing existing downstream sender [con: {}, link: {}]", client.getConnectionId(), client.getLinkId());
        resultHandler.handle(Future.succeededFuture());
    } else {
        removeSender(client);
        // register the result handler to be failed if the connection to the downstream container fails during
        // the attempt to create a downstream sender
        clientAttachHandlers.add(resultHandler);
        Future<Void> tracker = Future.future();
        tracker.setHandler(attempt -> {
            if (attempt.succeeded()) {
                logger.info("created downstream sender [con: {}, link: {}]", client.getConnectionId(), client.getLinkId());
            } else {
                logger.warn("can't create downstream sender [con: {}, link: {}]: {}", client.getConnectionId(), client.getLinkId(), attempt.cause().getMessage());
            }
            clientAttachHandlers.remove(resultHandler);
            resultHandler.handle(attempt);
        });
        final ResourceIdentifier targetAddress = ResourceIdentifier.fromString(client.getTargetAddress());
        createSender(targetAddress, replenishedSender -> handleFlow(replenishedSender, client), closeHook -> {
            removeSender(client);
            closeReceiver(client);
        }).compose(createdSender -> {
            addSender(client, createdSender);
            tracker.complete();
        }, tracker);
    }
}
Also used : ProtonConnection(io.vertx.proton.ProtonConnection) ProtonDelivery(io.vertx.proton.ProtonDelivery) LoggerFactory(org.slf4j.LoggerFactory) Autowired(org.springframework.beans.factory.annotation.Autowired) HashMap(java.util.HashMap) Constants(org.eclipse.hono.util.Constants) ArrayList(java.util.ArrayList) ConnectionFactory(org.eclipse.hono.connection.ConnectionFactory) ProtonClientOptions(io.vertx.proton.ProtonClientOptions) Map(java.util.Map) Qualifier(org.springframework.beans.factory.annotation.Qualifier) Message(org.apache.qpid.proton.message.Message) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) AsyncResult(io.vertx.core.AsyncResult) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) Vertx(io.vertx.core.Vertx) ProtonHelper(io.vertx.proton.ProtonHelper) ProtonQoS(io.vertx.proton.ProtonQoS) Future(io.vertx.core.Future) Objects(java.util.Objects) List(java.util.List) Component(org.springframework.stereotype.Component) ProtonSender(io.vertx.proton.ProtonSender) Handler(io.vertx.core.Handler) ProtonSender(io.vertx.proton.ProtonSender) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier)

Example 17 with ProtonSender

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

the class ForwardingDownstreamAdapter method processMessage.

@Override
public final void processMessage(final UpstreamReceiver client, final ProtonDelivery upstreamDelivery, final Message msg) {
    if (!running) {
        throw new IllegalStateException("adapter must be started first");
    }
    Objects.requireNonNull(client);
    Objects.requireNonNull(msg);
    Objects.requireNonNull(upstreamDelivery);
    ProtonSender sender = activeSenders.get(client);
    if (sender == null) {
        logger.info("no downstream sender for link [{}] available, discarding message and closing link with client", client.getLinkId());
        client.close(ErrorConditions.ERROR_NO_DOWNSTREAM_CONSUMER);
    } else if (sender.isOpen()) {
        if (sender.sendQueueFull()) {
            if (upstreamDelivery.remotelySettled()) {
                // sender has sent the message pre-settled, i.e. we can simply discard the message
                logger.debug("no downstream credit available for link [{}], discarding message [{}]", client.getLinkId(), msg.getMessageId());
                ProtonHelper.accepted(upstreamDelivery, true);
                metrics.incrementDiscardedMessages(sender.getTarget().getAddress());
            } else {
                // sender needs to be informed that we cannot process the message
                logger.debug("no downstream credit available for link [{}], releasing message [{}]", client.getLinkId(), msg.getMessageId());
                ProtonHelper.released(upstreamDelivery, true);
                metrics.incrementUndeliverableMessages(sender.getTarget().getAddress());
            }
        } else {
            logger.trace("forwarding message [id: {}, to: {}, content-type: {}] to downstream container [{}], credit available: {}, queued: {}", msg.getMessageId(), msg.getAddress(), msg.getContentType(), getDownstreamContainer(), sender.getCredit(), sender.getQueued());
            forwardMessage(sender, msg, upstreamDelivery);
            metrics.incrementProcessedMessages(sender.getTarget().getAddress());
        }
    } else {
        logger.warn("downstream sender for link [{}] is not open, discarding message and closing link with client", client.getLinkId());
        client.close(ErrorConditions.ERROR_NO_DOWNSTREAM_CONSUMER);
        onClientDetach(client);
        metrics.incrementDiscardedMessages(sender.getTarget().getAddress());
    }
}
Also used : ProtonSender(io.vertx.proton.ProtonSender)

Example 18 with ProtonSender

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

the class SenderFactoryImpl method newSender.

Future<ProtonSender> newSender(final ProtonConnection connection, final ProtonSession session, final ResourceIdentifier address, final ProtonQoS qos, final Handler<ProtonSender> sendQueueDrainHandler, final Handler<String> closeHook) {
    Future<ProtonSender> result = Future.future();
    ProtonSender sender = session.createSender(getTenantOnlyTargetAddress(address));
    sender.setQoS(qos);
    sender.setAutoSettle(true);
    sender.sendQueueDrainHandler(sendQueueDrainHandler);
    sender.openHandler(openAttempt -> {
        if (openAttempt.succeeded()) {
            LOG.debug("sender [{}] for container [{}] open", address, connection.getRemoteContainer());
            result.complete(openAttempt.result());
        } else {
            LOG.debug("could not open sender [{}] for container [{}]", address, connection.getRemoteContainer(), openAttempt.cause());
            result.fail(openAttempt.cause());
        }
    });
    sender.closeHandler(closed -> {
        if (closed.succeeded()) {
            LOG.debug("sender [{}] for container [{}] closed", address, connection.getRemoteContainer());
        } else {
            LOG.debug("sender [{}] for container [{}] closed: {}", address, connection.getRemoteContainer(), closed.cause().getMessage());
        }
        sender.close();
        if (closeHook != null) {
            closeHook.handle(address.getResourceId());
        }
    });
    sender.detachHandler(detached -> {
        if (detached.succeeded()) {
            LOG.debug("sender [{}] detached (with closed=false) by peer [{}]", address, connection.getRemoteContainer());
        } else {
            LOG.debug("sender [{}] detached (with closed=false) by peer [{}]: {}", address, connection.getRemoteContainer(), detached.cause().getMessage());
        }
        sender.close();
        if (closeHook != null) {
            closeHook.handle(address.getResourceId());
        }
    });
    sender.open();
    return result;
}
Also used : ProtonSender(io.vertx.proton.ProtonSender)

Example 19 with ProtonSender

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

the class ForwardingDownstreamAdapterTest method testHandleFlowForwardsDrainRequestUpstream.

/**
 * Verifies that <em>drain</em> requests received from the downstream container are forwarded
 * to upstream clients.
 */
@SuppressWarnings("unchecked")
@Test
public void testHandleFlowForwardsDrainRequestUpstream() {
    final UpstreamReceiver client = newClient();
    when(client.getTargetAddress()).thenReturn(targetAddress.toString());
    final ProtonSender drainingSender = newMockSender(true);
    // GIVEN an adapter with a connection to the downstream container and a client attached
    givenADownstreamAdapter();
    adapter.setDownstreamConnectionFactory(connectionFactory);
    adapter.start(Future.future());
    adapter.addSender(client, drainingSender);
    // WHEN the downstream sender drains the adapter
    adapter.handleFlow(drainingSender, client);
    // THEN assert that the upstream client has been drained
    verify(client).drain(anyLong(), any(Handler.class));
}
Also used : ProtonSender(io.vertx.proton.ProtonSender) Handler(io.vertx.core.Handler) Test(org.junit.Test)

Example 20 with ProtonSender

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

the class ForwardingDownstreamAdapterTest method testDownstreamDisconnectClosesUpstreamReceivers.

/**
 * Verifies that all links to upstream clients are closed when the connection to the
 * downstream container is lost.
 */
@Test
public void testDownstreamDisconnectClosesUpstreamReceivers() {
    final UpstreamReceiver client = newClient();
    final ProtonSender downstreamSender = newMockSender(false);
    // expect the connection factory to be invoked twice
    // first on initial connection
    // second on re-connect attempt
    HandlerCapturingConnectionFactory factory = new HandlerCapturingConnectionFactory(con, 2);
    // GIVEN an adapter connected to a downstream container
    givenADownstreamAdapter(downstreamSender);
    adapter.setDownstreamConnectionFactory(factory);
    adapter.start(Future.future());
    adapter.addSender(client, downstreamSender);
    // WHEN the downstream connection fails
    factory.getDisconnectHandler().handle(con);
    // THEN the adapter tries to reconnect to the downstream container and has closed all upstream receivers
    factory.await(1, TimeUnit.SECONDS);
    verify(client).close(any(ErrorCondition.class));
    assertTrue(adapter.isActiveSendersEmpty());
    assertTrue(adapter.isSendersPerConnectionEmpty());
}
Also used : ProtonSender(io.vertx.proton.ProtonSender) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) Test(org.junit.Test)

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