Search in sources :

Example 21 with ClientErrorException

use of org.eclipse.hono.client.ClientErrorException in project hono by eclipse.

the class AbstractHonoClient method createReceiver.

/**
 * Creates a receiver link.
 * <p>
 * The receiver will be created with its <em>autoAccept</em> property set to {@code true}.
 *
 * @param ctx The vert.x context to use for establishing the link.
 * @param clientConfig The configuration properties to use.
 * @param con The connection to create the link for.
 * @param sourceAddress The address to receive messages from.
 * @param qos The quality of service to use for the link.
 * @param messageHandler The handler to invoke with every message received.
 * @param closeHook The handler to invoke when the link is closed by the peer (may be {@code null}).
 * @return A future for the created link. The future will be completed once the link is open.
 *         The future will fail with a {@link ServiceInvocationException} if the link cannot be opened.
 * @throws NullPointerException if any of the arguments other than close hook is {@code null}.
 */
protected static final Future<ProtonReceiver> createReceiver(final Context ctx, final ClientConfigProperties clientConfig, final ProtonConnection con, final String sourceAddress, final ProtonQoS qos, final ProtonMessageHandler messageHandler, final Handler<String> closeHook) {
    Objects.requireNonNull(ctx);
    Objects.requireNonNull(clientConfig);
    Objects.requireNonNull(con);
    Objects.requireNonNull(sourceAddress);
    Objects.requireNonNull(qos);
    Objects.requireNonNull(messageHandler);
    final Future<ProtonReceiver> result = Future.future();
    ctx.runOnContext(go -> {
        final ProtonReceiver receiver = con.createReceiver(sourceAddress);
        receiver.attachments().set(KEY_LINK_ESTABLISHED, Boolean.class, Boolean.FALSE);
        receiver.setAutoAccept(true);
        receiver.setQoS(qos);
        receiver.setPrefetch(clientConfig.getInitialCredits());
        receiver.handler((delivery, message) -> {
            messageHandler.handle(delivery, message);
            if (LOG.isTraceEnabled()) {
                int remainingCredits = receiver.getCredit() - receiver.getQueued();
                LOG.trace("handling message [remotely settled: {}, queued messages: {}, remaining credit: {}]", delivery.remotelySettled(), receiver.getQueued(), remainingCredits);
            }
        });
        receiver.openHandler(recvOpen -> {
            if (recvOpen.succeeded()) {
                LOG.debug("receiver open [source: {}]", sourceAddress);
                receiver.attachments().set(KEY_LINK_ESTABLISHED, Boolean.class, Boolean.TRUE);
                result.complete(recvOpen.result());
            } else {
                final ErrorCondition error = receiver.getRemoteCondition();
                if (error == null) {
                    LOG.debug("opening receiver [{}] failed", sourceAddress, recvOpen.cause());
                    result.fail(new ClientErrorException(HttpURLConnection.HTTP_NOT_FOUND, "cannot open receiver", recvOpen.cause()));
                } else {
                    LOG.debug("opening receiver [{}] failed: {} - {}", sourceAddress, error.getCondition(), error.getDescription());
                    result.fail(StatusCodeMapper.from(error));
                }
            }
        });
        receiver.detachHandler(remoteDetached -> onRemoteDetach(receiver, con.getRemoteContainer(), false, closeHook));
        receiver.closeHandler(remoteClosed -> onRemoteDetach(receiver, con.getRemoteContainer(), true, closeHook));
        receiver.open();
    });
    return result;
}
Also used : ProtonReceiver(io.vertx.proton.ProtonReceiver) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) ClientErrorException(org.eclipse.hono.client.ClientErrorException)

Example 22 with ClientErrorException

use of org.eclipse.hono.client.ClientErrorException in project hono by eclipse.

the class AbstractHonoClient method createSender.

/**
 * Creates a sender link.
 *
 * @param ctx The vert.x context to use for establishing the link.
 * @param clientConfig The configuration properties to use.
 * @param con The connection to create the link for.
 * @param targetAddress The target address of the link.
 * @param qos The quality of service to use for the link.
 * @param closeHook The handler to invoke when the link is closed by the peer (may be {@code null}).
 * @return A future for the created link. The future will be completed once the link is open.
 *         The future will fail with a {@link ServiceInvocationException} if the link cannot be opened.
 * @throws NullPointerException if any of the arguments other than close hook is {@code null}.
 */
protected static final Future<ProtonSender> createSender(final Context ctx, final ClientConfigProperties clientConfig, final ProtonConnection con, final String targetAddress, final ProtonQoS qos, final Handler<String> closeHook) {
    Objects.requireNonNull(ctx);
    Objects.requireNonNull(clientConfig);
    Objects.requireNonNull(con);
    Objects.requireNonNull(targetAddress);
    Objects.requireNonNull(qos);
    final Future<ProtonSender> result = Future.future();
    ctx.runOnContext(create -> {
        final ProtonSender sender = con.createSender(targetAddress);
        sender.attachments().set(KEY_LINK_ESTABLISHED, Boolean.class, Boolean.FALSE);
        sender.setQoS(qos);
        sender.setAutoSettle(true);
        sender.openHandler(senderOpen -> {
            if (senderOpen.succeeded()) {
                LOG.debug("sender open [target: {}, sendQueueFull: {}]", targetAddress, sender.sendQueueFull());
                sender.attachments().set(KEY_LINK_ESTABLISHED, Boolean.class, Boolean.TRUE);
                // wait on credits a little time, if not already given
                if (sender.sendQueueFull()) {
                    ctx.owner().setTimer(clientConfig.getFlowLatency(), timerID -> {
                        LOG.debug("sender [target: {}] has {} credits after grace period of {}ms", targetAddress, sender.getCredit(), clientConfig.getFlowLatency());
                        result.complete(sender);
                    });
                } else {
                    result.complete(sender);
                }
            } else {
                final ErrorCondition error = sender.getRemoteCondition();
                if (error == null) {
                    LOG.debug("opening sender [{}] failed", targetAddress, senderOpen.cause());
                    result.fail(new ClientErrorException(HttpURLConnection.HTTP_NOT_FOUND, "cannot open sender", senderOpen.cause()));
                } else {
                    LOG.debug("opening sender [{}] failed: {} - {}", targetAddress, error.getCondition(), error.getDescription());
                    result.fail(StatusCodeMapper.from(error));
                }
            }
        });
        sender.detachHandler(remoteDetached -> onRemoteDetach(sender, con.getRemoteContainer(), false, closeHook));
        sender.closeHandler(remoteClosed -> onRemoteDetach(sender, con.getRemoteContainer(), true, closeHook));
        sender.open();
    });
    return result;
}
Also used : ProtonSender(io.vertx.proton.ProtonSender) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) ClientErrorException(org.eclipse.hono.client.ClientErrorException)

Example 23 with ClientErrorException

use of org.eclipse.hono.client.ClientErrorException in project hono by eclipse.

the class AbstractRequestResponseClient method sendRequest.

/**
 * Sends a request message via this client's sender link to the peer.
 * <p>
 * This method first checks if the sender has any credit left. If not, the result handler is failed immediately.
 * Otherwise, the request message is sent and a timer is started which fails the result handler,
 * if no response is received within <em>requestTimeoutMillis</em> milliseconds.
 *
 * @param request The message to send.
 * @param resultHandler The handler to notify about the outcome of the request.
 * @param cacheKey The key to use for caching the response (if the service allows caching).
 */
private final void sendRequest(final Message request, final Handler<AsyncResult<R>> resultHandler, final Object cacheKey) {
    context.runOnContext(req -> {
        if (sender.sendQueueFull()) {
            LOG.debug("cannot send request to peer, no credit left for link [target: {}]", targetAddress);
            resultHandler.handle(Future.failedFuture(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "no credit available for sending request")));
        } else {
            final Object correlationId = Optional.ofNullable(request.getCorrelationId()).orElse(request.getMessageId());
            final TriTuple<Handler<AsyncResult<R>>, Object, Object> handler = TriTuple.of(resultHandler, cacheKey, null);
            replyMap.put(correlationId, handler);
            sender.send(request, deliveryUpdated -> {
                if (Rejected.class.isInstance(deliveryUpdated.getRemoteState())) {
                    final Rejected rejected = (Rejected) deliveryUpdated.getRemoteState();
                    if (rejected.getError() != null) {
                        LOG.debug("service did not accept request [target address: {}, subject: {}, correlation ID: {}]: {}", targetAddress, request.getSubject(), correlationId, rejected.getError());
                        cancelRequest(correlationId, Future.failedFuture(StatusCodeMapper.from(rejected.getError())));
                    } else {
                        LOG.debug("service did not accept request [target address: {}, subject: {}, correlation ID: {}]", targetAddress, request.getSubject(), correlationId);
                        cancelRequest(correlationId, Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST)));
                    }
                } else if (Accepted.class.isInstance(deliveryUpdated.getRemoteState())) {
                    LOG.trace("service has accepted request [target address: {}, subject: {}, correlation ID: {}]", targetAddress, request.getSubject(), correlationId);
                } else {
                    LOG.debug("service did not accept request [target address: {}, subject: {}, correlation ID: {}]: {}", targetAddress, request.getSubject(), correlationId, deliveryUpdated.getRemoteState());
                    cancelRequest(correlationId, Future.failedFuture(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE)));
                }
            });
            if (requestTimeoutMillis > 0) {
                context.owner().setTimer(requestTimeoutMillis, tid -> {
                    cancelRequest(correlationId, Future.failedFuture(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "request timed out after " + requestTimeoutMillis + "ms")));
                });
            }
            if (LOG.isDebugEnabled()) {
                final String deviceId = MessageHelper.getDeviceId(request);
                if (deviceId == null) {
                    LOG.debug("sent request [target address: {}, subject: {}, correlation ID: {}] to service", targetAddress, request.getSubject(), correlationId);
                } else {
                    LOG.debug("sent request [target address: {}, subject: {}, correlation ID: {}, device ID: {}] to service", targetAddress, request.getSubject(), correlationId, deviceId);
                }
            }
        }
    });
}
Also used : Handler(io.vertx.core.Handler) ClientErrorException(org.eclipse.hono.client.ClientErrorException) JsonObject(io.vertx.core.json.JsonObject) ServerErrorException(org.eclipse.hono.client.ServerErrorException) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) Accepted(org.apache.qpid.proton.amqp.messaging.Accepted)

Example 24 with ClientErrorException

use of org.eclipse.hono.client.ClientErrorException 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 25 with ClientErrorException

use of org.eclipse.hono.client.ClientErrorException in project hono by eclipse.

the class ClaimsBasedAuthorizationService method isAuthorized.

@Override
public Future<Boolean> isAuthorized(final HonoUser user, final ResourceIdentifier resource, final Activity intent) {
    Objects.requireNonNull(user);
    Objects.requireNonNull(resource);
    Objects.requireNonNull(intent);
    if (user.isExpired()) {
        return Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_FORBIDDEN, "user information expired"));
    } else {
        return Future.succeededFuture(user.getAuthorities().isAuthorized(resource, intent));
    }
}
Also used : ClientErrorException(org.eclipse.hono.client.ClientErrorException)

Aggregations

ClientErrorException (org.eclipse.hono.client.ClientErrorException)32 JsonObject (io.vertx.core.json.JsonObject)19 Future (io.vertx.core.Future)16 HttpURLConnection (java.net.HttpURLConnection)16 Handler (io.vertx.core.Handler)14 AsyncResult (io.vertx.core.AsyncResult)13 Objects (java.util.Objects)12 ServerErrorException (org.eclipse.hono.client.ServerErrorException)10 TenantConstants (org.eclipse.hono.util.TenantConstants)9 EventBusService (org.eclipse.hono.service.EventBusService)8 EventBusMessage (org.eclipse.hono.util.EventBusMessage)8 Vertx (io.vertx.core.Vertx)6 Buffer (io.vertx.core.buffer.Buffer)6 ProtonDelivery (io.vertx.proton.ProtonDelivery)6 HonoClient (org.eclipse.hono.client.HonoClient)6 MqttEndpoint (io.vertx.mqtt.MqttEndpoint)5 MqttServer (io.vertx.mqtt.MqttServer)5 Optional (java.util.Optional)5 TimeUnit (java.util.concurrent.TimeUnit)5 Message (org.apache.qpid.proton.message.Message)5