Search in sources :

Example 96 with Handler

use of io.vertx.core.Handler in project hono by eclipse.

the class HonoClientImpl method getOrCreateRequestResponseClient.

/**
 * Gets an existing or creates a new request-response client for a particular service.
 *
 * @param key The key to look-up the client by.
 * @param clientSupplier A consumer for an attempt to create a new client.
 * @param resultHandler The handler to inform about the outcome of the operation.
 */
void getOrCreateRequestResponseClient(final String key, final Supplier<Future<RequestResponseClient>> clientSupplier, final Handler<AsyncResult<RequestResponseClient>> resultHandler) {
    context.runOnContext(get -> {
        final RequestResponseClient client = activeRequestResponseClients.get(key);
        if (client != null && client.isOpen()) {
            LOG.debug("reusing existing client [target: {}]", key);
            resultHandler.handle(Future.succeededFuture(client));
        } else if (!creationLocks.computeIfAbsent(key, k -> Boolean.FALSE)) {
            // register a handler to be notified if the underlying connection to the server fails
            // so that we can fail the result handler passed in
            final Handler<Void> connectionFailureHandler = connectionLost -> {
                // remove lock so that next attempt to open a sender doesn't fail
                creationLocks.remove(key);
                resultHandler.handle(Future.failedFuture(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "no connection to service")));
            };
            creationRequests.add(connectionFailureHandler);
            creationLocks.put(key, Boolean.TRUE);
            LOG.debug("creating new client for {}", key);
            clientSupplier.get().setHandler(creationAttempt -> {
                if (creationAttempt.succeeded()) {
                    LOG.debug("successfully created new client for {}", key);
                    activeRequestResponseClients.put(key, creationAttempt.result());
                } else {
                    LOG.debug("failed to create new client for {}", key, creationAttempt.cause());
                    activeRequestResponseClients.remove(key);
                }
                creationLocks.remove(key);
                creationRequests.remove(connectionFailureHandler);
                resultHandler.handle(creationAttempt);
            });
        } else {
            LOG.debug("already trying to create a client for {}", key);
            resultHandler.handle(Future.failedFuture(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "no connection to service")));
        }
    });
}
Also used : HttpURLConnection(java.net.HttpURLConnection) RequestResponseClient(org.eclipse.hono.client.RequestResponseClient) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonDelivery(io.vertx.proton.ProtonDelivery) LoggerFactory(org.slf4j.LoggerFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) MessageConsumer(org.eclipse.hono.client.MessageConsumer) ClientErrorException(org.eclipse.hono.client.ClientErrorException) Supplier(java.util.function.Supplier) Constants(org.eclipse.hono.util.Constants) Context(io.vertx.core.Context) ArrayList(java.util.ArrayList) ConnectionFactory(org.eclipse.hono.connection.ConnectionFactory) CredentialsClient(org.eclipse.hono.client.CredentialsClient) ProtonClientOptions(io.vertx.proton.ProtonClientOptions) TenantClient(org.eclipse.hono.client.TenantClient) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ConnectionFactoryBuilder(org.eclipse.hono.connection.ConnectionFactoryImpl.ConnectionFactoryBuilder) Map(java.util.Map) MessageSender(org.eclipse.hono.client.MessageSender) BiConsumer(java.util.function.BiConsumer) Message(org.apache.qpid.proton.message.Message) RegistrationClient(org.eclipse.hono.client.RegistrationClient) AsyncResult(io.vertx.core.AsyncResult) HonoClient(org.eclipse.hono.client.HonoClient) ClientConfigProperties(org.eclipse.hono.config.ClientConfigProperties) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) Vertx(io.vertx.core.Vertx) ServerErrorException(org.eclipse.hono.client.ServerErrorException) CacheProvider(org.eclipse.hono.cache.CacheProvider) Future(io.vertx.core.Future) Objects(java.util.Objects) TimeUnit(java.util.concurrent.TimeUnit) Consumer(java.util.function.Consumer) CountDownLatch(java.util.concurrent.CountDownLatch) List(java.util.List) Handler(io.vertx.core.Handler) RequestResponseClient(org.eclipse.hono.client.RequestResponseClient) Handler(io.vertx.core.Handler) ServerErrorException(org.eclipse.hono.client.ServerErrorException)

Example 97 with Handler

use of io.vertx.core.Handler in project hono by eclipse.

the class HonoClientImpl method getOrCreateSender.

Future<MessageSender> getOrCreateSender(final String key, final Supplier<Future<MessageSender>> newSenderSupplier) {
    final Future<MessageSender> result = Future.future();
    context.runOnContext(get -> {
        final MessageSender sender = activeSenders.get(key);
        if (sender != null && sender.isOpen()) {
            LOG.debug("reusing existing message sender [target: {}, credit: {}]", key, sender.getCredit());
            result.complete(sender);
        } else if (!creationLocks.computeIfAbsent(key, k -> Boolean.FALSE)) {
            // register a handler to be notified if the underlying connection to the server fails
            // so that we can fail the result handler passed in
            final Handler<Void> connectionFailureHandler = connectionLost -> {
                // remove lock so that next attempt to open a sender doesn't fail
                creationLocks.remove(key);
                result.tryFail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "no connection to service"));
            };
            creationRequests.add(connectionFailureHandler);
            creationLocks.put(key, Boolean.TRUE);
            LOG.debug("creating new message sender for {}", key);
            newSenderSupplier.get().setHandler(creationAttempt -> {
                creationLocks.remove(key);
                creationRequests.remove(connectionFailureHandler);
                if (creationAttempt.succeeded()) {
                    MessageSender newSender = creationAttempt.result();
                    LOG.debug("successfully created new message sender for {}", key);
                    activeSenders.put(key, newSender);
                    result.tryComplete(newSender);
                } else {
                    LOG.debug("failed to create new message sender for {}", key, creationAttempt.cause());
                    activeSenders.remove(key);
                    result.tryFail(creationAttempt.cause());
                }
            });
        } else {
            LOG.debug("already trying to create a message sender for {}", key);
            result.fail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "no connection to service"));
        }
    });
    return result;
}
Also used : HttpURLConnection(java.net.HttpURLConnection) RequestResponseClient(org.eclipse.hono.client.RequestResponseClient) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonDelivery(io.vertx.proton.ProtonDelivery) LoggerFactory(org.slf4j.LoggerFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) MessageConsumer(org.eclipse.hono.client.MessageConsumer) ClientErrorException(org.eclipse.hono.client.ClientErrorException) Supplier(java.util.function.Supplier) Constants(org.eclipse.hono.util.Constants) Context(io.vertx.core.Context) ArrayList(java.util.ArrayList) ConnectionFactory(org.eclipse.hono.connection.ConnectionFactory) CredentialsClient(org.eclipse.hono.client.CredentialsClient) ProtonClientOptions(io.vertx.proton.ProtonClientOptions) TenantClient(org.eclipse.hono.client.TenantClient) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ConnectionFactoryBuilder(org.eclipse.hono.connection.ConnectionFactoryImpl.ConnectionFactoryBuilder) Map(java.util.Map) MessageSender(org.eclipse.hono.client.MessageSender) BiConsumer(java.util.function.BiConsumer) Message(org.apache.qpid.proton.message.Message) RegistrationClient(org.eclipse.hono.client.RegistrationClient) AsyncResult(io.vertx.core.AsyncResult) HonoClient(org.eclipse.hono.client.HonoClient) ClientConfigProperties(org.eclipse.hono.config.ClientConfigProperties) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) Vertx(io.vertx.core.Vertx) ServerErrorException(org.eclipse.hono.client.ServerErrorException) CacheProvider(org.eclipse.hono.cache.CacheProvider) Future(io.vertx.core.Future) Objects(java.util.Objects) TimeUnit(java.util.concurrent.TimeUnit) Consumer(java.util.function.Consumer) CountDownLatch(java.util.concurrent.CountDownLatch) List(java.util.List) Handler(io.vertx.core.Handler) MessageSender(org.eclipse.hono.client.MessageSender) Handler(io.vertx.core.Handler) ServerErrorException(org.eclipse.hono.client.ServerErrorException)

Example 98 with Handler

use of io.vertx.core.Handler in project hono by eclipse.

the class HonoClientImpl method connect.

private void connect(final ProtonClientOptions options, final Handler<AsyncResult<HonoClient>> connectionHandler, final Handler<ProtonConnection> disconnectHandler) {
    context.runOnContext(connect -> {
        if (isConnectedInternal()) {
            LOG.debug("already connected to server [{}:{}]", connectionFactory.getHost(), connectionFactory.getPort());
            connectionHandler.handle(Future.succeededFuture(this));
        } else if (connecting.compareAndSet(false, true)) {
            if (options == null) {
                // by default, try to re-connect forever
                clientOptions = new ProtonClientOptions().setConnectTimeout(200).setReconnectAttempts(-1).setReconnectInterval(Constants.DEFAULT_RECONNECT_INTERVAL_MILLIS);
            } else {
                clientOptions = options;
            }
            connectionFactory.connect(clientOptions, remoteClose -> onRemoteClose(remoteClose, disconnectHandler), failedConnection -> onRemoteDisconnect(failedConnection, disconnectHandler), conAttempt -> {
                connecting.compareAndSet(true, false);
                if (conAttempt.failed()) {
                    if (conAttempt.cause() instanceof SecurityException) {
                        // SASL handshake has failed
                        connectionHandler.handle(Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_UNAUTHORIZED, "failed to authenticate with server")));
                    } else {
                        reconnect(conAttempt.cause(), connectionHandler, disconnectHandler);
                    }
                } else {
                    // make sure we try to re-connect as often as we tried to connect initially
                    reconnectAttempts = new AtomicInteger(0);
                    final ProtonConnection newConnection = conAttempt.result();
                    if (shuttingDown.get()) {
                        // if client was shut down in the meantime, we need to immediately
                        // close again the newly created connection
                        newConnection.closeHandler(null);
                        newConnection.disconnectHandler(null);
                        newConnection.close();
                        connectionHandler.handle(Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_CONFLICT, "client is already shut down")));
                    } else {
                        setConnection(newConnection);
                        connectionHandler.handle(Future.succeededFuture(this));
                    }
                }
            });
        } else {
            LOG.debug("already trying to connect to server ...");
            connectionHandler.handle(Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_CONFLICT, "already connecting to server")));
        }
    });
}
Also used : HttpURLConnection(java.net.HttpURLConnection) RequestResponseClient(org.eclipse.hono.client.RequestResponseClient) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonDelivery(io.vertx.proton.ProtonDelivery) LoggerFactory(org.slf4j.LoggerFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) MessageConsumer(org.eclipse.hono.client.MessageConsumer) ClientErrorException(org.eclipse.hono.client.ClientErrorException) Supplier(java.util.function.Supplier) Constants(org.eclipse.hono.util.Constants) Context(io.vertx.core.Context) ArrayList(java.util.ArrayList) ConnectionFactory(org.eclipse.hono.connection.ConnectionFactory) CredentialsClient(org.eclipse.hono.client.CredentialsClient) ProtonClientOptions(io.vertx.proton.ProtonClientOptions) TenantClient(org.eclipse.hono.client.TenantClient) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ConnectionFactoryBuilder(org.eclipse.hono.connection.ConnectionFactoryImpl.ConnectionFactoryBuilder) Map(java.util.Map) MessageSender(org.eclipse.hono.client.MessageSender) BiConsumer(java.util.function.BiConsumer) Message(org.apache.qpid.proton.message.Message) RegistrationClient(org.eclipse.hono.client.RegistrationClient) AsyncResult(io.vertx.core.AsyncResult) HonoClient(org.eclipse.hono.client.HonoClient) ClientConfigProperties(org.eclipse.hono.config.ClientConfigProperties) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) Vertx(io.vertx.core.Vertx) ServerErrorException(org.eclipse.hono.client.ServerErrorException) CacheProvider(org.eclipse.hono.cache.CacheProvider) Future(io.vertx.core.Future) Objects(java.util.Objects) TimeUnit(java.util.concurrent.TimeUnit) Consumer(java.util.function.Consumer) CountDownLatch(java.util.concurrent.CountDownLatch) List(java.util.List) Handler(io.vertx.core.Handler) ProtonConnection(io.vertx.proton.ProtonConnection) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ClientErrorException(org.eclipse.hono.client.ClientErrorException) ProtonClientOptions(io.vertx.proton.ProtonClientOptions)

Example 99 with Handler

use of io.vertx.core.Handler in project hono by eclipse.

the class AbstractHonoClientTest method testCreateReceiverFails.

@SuppressWarnings({ "unchecked", "rawtypes" })
private void testCreateReceiverFails(final Supplier<ErrorCondition> errorSupplier, final Predicate<Throwable> failureAssertion) {
    final Record attachments = new RecordImpl();
    final ProtonReceiver receiver = mock(ProtonReceiver.class);
    when(receiver.getRemoteCondition()).thenReturn(errorSupplier.get());
    when(receiver.attachments()).thenReturn(attachments);
    final ProtonConnection con = mock(ProtonConnection.class);
    when(con.createReceiver(anyString())).thenReturn(receiver);
    final Future<ProtonReceiver> result = AbstractHonoClient.createReceiver(context, props, con, "source", ProtonQoS.AT_LEAST_ONCE, (delivery, msg) -> {
    }, null);
    final ArgumentCaptor<Handler> openHandler = ArgumentCaptor.forClass(Handler.class);
    verify(receiver).openHandler(openHandler.capture());
    openHandler.getValue().handle(Future.failedFuture(new IllegalStateException()));
    assertTrue(result.failed());
    assertTrue(failureAssertion.test(result.cause()));
}
Also used : ProtonReceiver(io.vertx.proton.ProtonReceiver) 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 100 with Handler

use of io.vertx.core.Handler in project hono by eclipse.

the class AbstractRequestResponseClientTest method testCancelRequestFailsResponseHandler.

/**
 * Verifies that the client cancels and fails a request for which no response
 * has been received after a certain amount of time. The request is then
 * failed with a {@link ServerErrorException}.
 *
 * @param ctx The vert.x test context.
 */
@SuppressWarnings("unchecked")
@Test
public void testCancelRequestFailsResponseHandler(final TestContext ctx) {
    // GIVEN a request-response client which times out requests after 200 ms
    client.setRequestTimeout(200);
    // WHEN no response is received for a request sent to the peer
    doAnswer(invocation -> {
        // do not wait 200ms before running the timeout task but instead
        // run it immediately
        Handler<Long> task = invocation.getArgument(1);
        task.handle(1L);
        return null;
    }).when(vertx).setTimer(anyLong(), any(Handler.class));
    final Async requestFailure = ctx.async();
    client.createAndSendRequest("request", null, (JsonObject) null, ctx.asyncAssertFailure(t -> {
        ctx.assertTrue(ServerErrorException.class.isInstance(t));
        requestFailure.complete();
    }));
    // THEN the request handler is failed
    requestFailure.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) Async(io.vertx.ext.unit.Async) ArgumentMatchers.anyLong(org.mockito.ArgumentMatchers.anyLong) Handler(io.vertx.core.Handler) Test(org.junit.Test)

Aggregations

Handler (io.vertx.core.Handler)119 Test (org.junit.Test)78 Future (io.vertx.core.Future)67 Vertx (io.vertx.core.Vertx)59 AsyncResult (io.vertx.core.AsyncResult)57 Context (io.vertx.core.Context)52 Buffer (io.vertx.core.buffer.Buffer)48 Async (io.vertx.ext.unit.Async)41 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)39 Map (java.util.Map)38 TestContext (io.vertx.ext.unit.TestContext)37 VertxUnitRunner (io.vertx.ext.unit.junit.VertxUnitRunner)36 RunWith (org.junit.runner.RunWith)36 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)34 Collections (java.util.Collections)33 JsonObject (io.vertx.core.json.JsonObject)31 HttpURLConnection (java.net.HttpURLConnection)31 Before (org.junit.Before)31 StandardCharsets (java.nio.charset.StandardCharsets)29 TimeUnit (java.util.concurrent.TimeUnit)29