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")));
}
});
}
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;
}
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")));
}
});
}
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()));
}
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();
}
Aggregations