Search in sources :

Example 96 with Future

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

the class IntegrationTestSupport method deleteTenantKafkaTopics.

private Future<Void> deleteTenantKafkaTopics(final List<String> tenantsToDelete) {
    if (!isUsingKafkaMessaging()) {
        return Future.succeededFuture();
    }
    // topics for the given tenants are not deleted right away: It could be that the offset-commit interval of the CommandRouter
    // command consumer (5s) hasn't elapsed yet and it has to be avoided to delete the topics before the consumer has
    // committed corresponding offsets (otherwise the consumer will retry the commit for some time and be blocked during that time)
    final Promise<Void> tenantTopicsDeletionDonePromise = Promise.promise();
    tenantsToDeleteTopicsForAfterDelay.add(Pair.of(tenantsToDelete, Instant.now()));
    final List<String> tenantsToDeleteTopicsForNow = new LinkedList<>();
    final Instant nowMinusCommitInterval = Instant.now().minus(// commit interval with added buffer
    AsyncHandlingAutoCommitKafkaConsumer.DEFAULT_COMMIT_INTERVAL.plusSeconds(1));
    final Iterator<Pair<List<String>, Instant>> iterator = tenantsToDeleteTopicsForAfterDelay.iterator();
    while (iterator.hasNext()) {
        final Pair<List<String>, Instant> tenantsToDeleteAndInstantPair = iterator.next();
        if (tenantsToDeleteAndInstantPair.two().isBefore(nowMinusCommitInterval)) {
            tenantsToDeleteTopicsForNow.addAll(tenantsToDeleteAndInstantPair.one());
            iterator.remove();
        }
    }
    if (!tenantsToDeleteTopicsForNow.isEmpty()) {
        final KafkaAdminClient adminClient = KafkaAdminClient.create(vertx, getKafkaAdminClientConfig().getAdminClientConfig("test"));
        final Promise<Void> adminClientClosedPromise = Promise.promise();
        LOGGER.debug("deleting topics for temporary tenants {}", tenantsToDeleteTopicsForNow);
        final List<String> topicNames = tenantsToDeleteTopicsForNow.stream().flatMap(tenant -> HonoTopic.Type.MESSAGING_API_TYPES.stream().map(type -> new HonoTopic(type, tenant).toString())).collect(Collectors.toList());
        adminClient.deleteTopics(topicNames, ar -> {
            // note that the result will probably have failed with an UnknownTopicOrPartitionException here;
            // not necessarily all tenant topics may have been created before
            LOGGER.debug("done triggering deletion of topics for tenants {}", tenantsToDeleteTopicsForNow);
            adminClient.close(adminClientClosedPromise);
        });
        adminClientClosedPromise.future().recover(thr -> {
            LOGGER.warn("error closing Kafka admin client", thr);
            return Future.succeededFuture();
        }).onComplete(tenantTopicsDeletionDonePromise);
    } else {
        tenantTopicsDeletionDonePromise.complete();
    }
    return tenantTopicsDeletionDonePromise.future();
}
Also used : HttpURLConnection(java.net.HttpURLConnection) X509Certificate(java.security.cert.X509Certificate) KeyPair(java.security.KeyPair) ApplicationClient(org.eclipse.hono.application.client.ApplicationClient) Arrays(java.util.Arrays) MessagingKafkaConsumerConfigProperties(org.eclipse.hono.client.kafka.consumer.MessagingKafkaConsumerConfigProperties) DownstreamMessage(org.eclipse.hono.application.client.DownstreamMessage) MessagingKafkaProducerConfigProperties(org.eclipse.hono.client.kafka.producer.MessagingKafkaProducerConfigProperties) TenantConstants(org.eclipse.hono.util.TenantConstants) LoggerFactory(org.slf4j.LoggerFactory) TimeoutException(java.util.concurrent.TimeoutException) VertxTools(org.eclipse.hono.test.VertxTools) InetAddress(java.net.InetAddress) GeneralSecurityException(java.security.GeneralSecurityException) MessagingType(org.eclipse.hono.util.MessagingType) PskCredential(org.eclipse.hono.service.management.credentials.PskCredential) ProtonBasedApplicationClient(org.eclipse.hono.application.client.amqp.ProtonBasedApplicationClient) Map(java.util.Map) Pair(org.eclipse.hono.util.Pair) JsonObject(io.vertx.core.json.JsonObject) ClientConfigProperties(org.eclipse.hono.config.ClientConfigProperties) KeyPairGenerator(java.security.KeyPairGenerator) Device(org.eclipse.hono.service.management.device.Device) MessageContext(org.eclipse.hono.application.client.MessageContext) Truth.assertWithMessage(com.google.common.truth.Truth.assertWithMessage) CachingKafkaProducerFactory(org.eclipse.hono.client.kafka.producer.CachingKafkaProducerFactory) Set(java.util.Set) ConsumerConfig(org.apache.kafka.clients.consumer.ConsumerConfig) UUID(java.util.UUID) Instant(java.time.Instant) MessageHelper(org.eclipse.hono.util.MessageHelper) RequestResponseApiConstants(org.eclipse.hono.util.RequestResponseApiConstants) Collectors(java.util.stream.Collectors) EventConstants(org.eclipse.hono.util.EventConstants) Future(io.vertx.core.Future) StandardCharsets(java.nio.charset.StandardCharsets) AsyncHandlingAutoCommitKafkaConsumer(org.eclipse.hono.client.kafka.consumer.AsyncHandlingAutoCommitKafkaConsumer) Objects(java.util.Objects) Base64(java.util.Base64) List(java.util.List) KafkaProducerFactory(org.eclipse.hono.client.kafka.producer.KafkaProducerFactory) Buffer(io.vertx.core.buffer.Buffer) MessageProperties(org.eclipse.hono.application.client.MessageProperties) Optional(java.util.Optional) Checkpoint(io.vertx.junit5.Checkpoint) Queue(java.util.Queue) VertxTestContext(io.vertx.junit5.VertxTestContext) HttpResponse(io.vertx.ext.web.client.HttpResponse) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Credentials(org.eclipse.hono.service.management.credentials.Credentials) HashMap(java.util.HashMap) OptionalInt(java.util.OptionalInt) Function(java.util.function.Function) Constants(org.eclipse.hono.util.Constants) TimeUntilDisconnectNotification(org.eclipse.hono.util.TimeUntilDisconnectNotification) HashSet(java.util.HashSet) CompositeFuture(io.vertx.core.CompositeFuture) KafkaAdminClientConfigProperties(org.eclipse.hono.client.kafka.KafkaAdminClientConfigProperties) LinkedList(java.util.LinkedList) HonoConnection(org.eclipse.hono.client.HonoConnection) CommandConstants(org.eclipse.hono.util.CommandConstants) ProducerConfig(org.apache.kafka.clients.producer.ProducerConfig) RegistryManagementConstants(org.eclipse.hono.util.RegistryManagementConstants) Strings(org.eclipse.hono.util.Strings) Logger(org.slf4j.Logger) Iterator(java.util.Iterator) Promise(io.vertx.core.Promise) KafkaApplicationClientImpl(org.eclipse.hono.application.client.kafka.impl.KafkaApplicationClientImpl) Vertx(io.vertx.core.Vertx) Truth.assertThat(com.google.common.truth.Truth.assertThat) ExecutionException(java.util.concurrent.ExecutionException) TimeUnit(java.util.concurrent.TimeUnit) HonoTopic(org.eclipse.hono.client.kafka.HonoTopic) JsonArray(io.vertx.core.json.JsonArray) MessageConsumer(org.eclipse.hono.application.client.MessageConsumer) SendMessageTimeoutException(org.eclipse.hono.client.SendMessageTimeoutException) SendMessageSampler(org.eclipse.hono.client.SendMessageSampler) NoopSpan(io.opentracing.noop.NoopSpan) GenericSenderLink(org.eclipse.hono.client.amqp.GenericSenderLink) Handler(io.vertx.core.Handler) PasswordCredential(org.eclipse.hono.service.management.credentials.PasswordCredential) KafkaAdminClient(io.vertx.kafka.admin.KafkaAdminClient) KafkaAdminClient(io.vertx.kafka.admin.KafkaAdminClient) Instant(java.time.Instant) HonoTopic(org.eclipse.hono.client.kafka.HonoTopic) LinkedList(java.util.LinkedList) List(java.util.List) LinkedList(java.util.LinkedList) KeyPair(java.security.KeyPair) Pair(org.eclipse.hono.util.Pair)

Example 97 with Future

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

the class VertxBasedAmqpProtocolAdapter method handleBeforeCredentialsValidation.

/**
 * Handles any operations that should be invoked as part of the authentication process after the credentials got
 * determined and before they get validated. Can be used to perform checks using the credentials and tenant
 * information before the potentially expensive credentials validation is done
 * <p>
 * The default implementation updates the trace sampling priority in the execution context tracing span.
 * <p>
 * Subclasses should override this method in order to perform additional operations after calling this super method.
 *
 * @param credentials The credentials.
 * @param executionContext The execution context, including the TenantObject.
 * @return A future indicating the outcome of the operation. A failed future will fail the authentication attempt.
 */
protected Future<Void> handleBeforeCredentialsValidation(final DeviceCredentials credentials, final SaslResponseContext executionContext) {
    final String tenantId = credentials.getTenantId();
    final Span span = executionContext.getTracingSpan();
    final String authId = credentials.getAuthId();
    return getTenantConfiguration(tenantId, span.context()).recover(t -> Future.failedFuture(CredentialsApiAuthProvider.mapNotFoundToBadCredentialsException(t))).compose(tenantObject -> {
        TracingHelper.setDeviceTags(span, tenantId, null, authId);
        final OptionalInt traceSamplingPriority = TenantTraceSamplingHelper.applyTraceSamplingPriority(tenantObject, authId, span);
        executionContext.getProtonConnection().attachments().set(AmqpAdapterConstants.KEY_TRACE_SAMPLING_PRIORITY, OptionalInt.class, traceSamplingPriority);
        return Future.succeededFuture();
    });
}
Also used : HttpURLConnection(java.net.HttpURLConnection) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonReceiver(io.vertx.proton.ProtonReceiver) LifecycleChange(org.eclipse.hono.notification.deviceregistry.LifecycleChange) DeviceChangeNotification(org.eclipse.hono.notification.deviceregistry.DeviceChangeNotification) Tags(io.opentracing.tag.Tags) ProtonServer(io.vertx.proton.ProtonServer) HonoProtonHelper(org.eclipse.hono.util.HonoProtonHelper) ProcessingOutcome(org.eclipse.hono.service.metric.MetricsTags.ProcessingOutcome) EndpointType(org.eclipse.hono.service.metric.MetricsTags.EndpointType) Modified(org.apache.qpid.proton.amqp.messaging.Modified) DeviceCredentials(org.eclipse.hono.adapter.auth.device.DeviceCredentials) Map(java.util.Map) DeliveryState(org.apache.qpid.proton.amqp.transport.DeliveryState) AuthorizationException(org.eclipse.hono.adapter.AuthorizationException) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) Fields(io.opentracing.log.Fields) AmqpError(org.apache.qpid.proton.amqp.transport.AmqpError) TracingHelper(org.eclipse.hono.tracing.TracingHelper) ProtonSaslAuthenticatorFactory(io.vertx.proton.sasl.ProtonSaslAuthenticatorFactory) AllDevicesOfTenantDeletedNotification(org.eclipse.hono.notification.deviceregistry.AllDevicesOfTenantDeletedNotification) TenantServiceBasedX509Authentication(org.eclipse.hono.adapter.auth.device.TenantServiceBasedX509Authentication) Predicate(java.util.function.Predicate) Collection(java.util.Collection) CommandContext(org.eclipse.hono.client.command.CommandContext) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) ProtonQoS(io.vertx.proton.ProtonQoS) MessageHelper(org.eclipse.hono.util.MessageHelper) Collectors(java.util.stream.Collectors) Future(io.vertx.core.Future) Device(org.eclipse.hono.auth.Device) Objects(java.util.Objects) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) List(java.util.List) QoS(org.eclipse.hono.service.metric.MetricsTags.QoS) TenantTraceSamplingHelper(org.eclipse.hono.tracing.TenantTraceSamplingHelper) CommandConsumer(org.eclipse.hono.client.command.CommandConsumer) Optional(java.util.Optional) Span(io.opentracing.Span) ProtonSender(io.vertx.proton.ProtonSender) NotificationEventBusSupport(org.eclipse.hono.notification.NotificationEventBusSupport) ProtonLink(io.vertx.proton.ProtonLink) Accepted(org.apache.qpid.proton.amqp.messaging.Accepted) ProtonServerOptions(io.vertx.proton.ProtonServerOptions) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) ConnectionLimitManager(org.eclipse.hono.adapter.limiting.ConnectionLimitManager) Command(org.eclipse.hono.client.command.Command) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) ClientErrorException(org.eclipse.hono.client.ClientErrorException) AdapterDisabledException(org.eclipse.hono.adapter.AdapterDisabledException) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) OptionalInt(java.util.OptionalInt) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) Commands(org.eclipse.hono.client.command.Commands) Constants(org.eclipse.hono.util.Constants) CompositeFuture(io.vertx.core.CompositeFuture) ProtonSession(io.vertx.proton.ProtonSession) Symbol(org.apache.qpid.proton.amqp.Symbol) AdapterConnectionsExceededException(org.eclipse.hono.adapter.AdapterConnectionsExceededException) Target(org.apache.qpid.proton.amqp.transport.Target) UnsignedLong(org.apache.qpid.proton.amqp.UnsignedLong) Message(org.apache.qpid.proton.message.Message) HttpUtils(org.eclipse.hono.service.http.HttpUtils) AsyncResult(io.vertx.core.AsyncResult) CommandConstants(org.eclipse.hono.util.CommandConstants) TenantChangeNotification(org.eclipse.hono.notification.deviceregistry.TenantChangeNotification) Strings(org.eclipse.hono.util.Strings) UsernamePasswordAuthProvider(org.eclipse.hono.adapter.auth.device.UsernamePasswordAuthProvider) CredentialsApiAuthProvider(org.eclipse.hono.adapter.auth.device.CredentialsApiAuthProvider) AbstractProtocolAdapterBase(org.eclipse.hono.adapter.AbstractProtocolAdapterBase) Direction(org.eclipse.hono.service.metric.MetricsTags.Direction) Promise(io.vertx.core.Promise) ServerErrorException(org.eclipse.hono.client.ServerErrorException) ProtonHelper(io.vertx.proton.ProtonHelper) Sample(io.micrometer.core.instrument.Timer.Sample) Released(org.apache.qpid.proton.amqp.messaging.Released) CommandResponse(org.eclipse.hono.client.command.CommandResponse) TenantObject(org.eclipse.hono.util.TenantObject) SpanContext(io.opentracing.SpanContext) Source(org.apache.qpid.proton.amqp.transport.Source) ConnectionAttemptOutcome(org.eclipse.hono.service.metric.MetricsTags.ConnectionAttemptOutcome) MemoryBasedConnectionLimitStrategy(org.eclipse.hono.adapter.limiting.MemoryBasedConnectionLimitStrategy) X509AuthProvider(org.eclipse.hono.adapter.auth.device.X509AuthProvider) Handler(io.vertx.core.Handler) Collections(java.util.Collections) DefaultConnectionLimitManager(org.eclipse.hono.adapter.limiting.DefaultConnectionLimitManager) OptionalInt(java.util.OptionalInt) Span(io.opentracing.Span)

Example 98 with Future

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

the class VertxBasedAmqpProtocolAdapter method createCommandConsumer.

private Future<CommandConsumer> createCommandConsumer(final ProtonSender sender, final ResourceIdentifier sourceAddress, final Device authenticatedDevice, final Span span) {
    final Handler<CommandContext> commandHandler = commandContext -> {
        final Sample timer = metrics.startTimer();
        addMicrometerSample(commandContext, timer);
        Tags.COMPONENT.set(commandContext.getTracingSpan(), getTypeName());
        final Command command = commandContext.getCommand();
        final Future<TenantObject> tenantTracker = getTenantConfiguration(sourceAddress.getTenantId(), commandContext.getTracingContext());
        tenantTracker.compose(tenantObject -> {
            if (!command.isValid()) {
                return Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "malformed command message"));
            }
            if (!HonoProtonHelper.isLinkOpenAndConnected(sender)) {
                return Future.failedFuture(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "sender link is not open"));
            }
            return checkMessageLimit(tenantObject, command.getPayloadSize(), commandContext.getTracingContext());
        }).compose(success -> {
            // check the via-gateways, ensuring that the gateway may act on behalf of the device at this point in time
            if (authenticatedDevice != null && !authenticatedDevice.getDeviceId().equals(sourceAddress.getResourceId())) {
                return getRegistrationAssertion(authenticatedDevice.getTenantId(), sourceAddress.getResourceId(), authenticatedDevice, commandContext.getTracingContext());
            }
            return Future.succeededFuture();
        }).compose(success -> {
            onCommandReceived(tenantTracker.result(), sender, commandContext);
            return Future.succeededFuture();
        }).otherwise(failure -> {
            if (failure instanceof ClientErrorException) {
                commandContext.reject(failure);
            } else {
                commandContext.release(failure);
            }
            metrics.reportCommand(command.isOneWay() ? Direction.ONE_WAY : Direction.REQUEST, sourceAddress.getTenantId(), tenantTracker.result(), ProcessingOutcome.from(failure), command.getPayloadSize(), timer);
            return null;
        });
    };
    final Future<RegistrationAssertion> tokenTracker = Optional.ofNullable(authenticatedDevice).map(v -> getRegistrationAssertion(authenticatedDevice.getTenantId(), sourceAddress.getResourceId(), authenticatedDevice, span.context())).orElseGet(Future::succeededFuture);
    if (authenticatedDevice != null && !authenticatedDevice.getDeviceId().equals(sourceAddress.getResourceId())) {
        // gateway scenario
        return tokenTracker.compose(v -> getCommandConsumerFactory().createCommandConsumer(sourceAddress.getTenantId(), sourceAddress.getResourceId(), authenticatedDevice.getDeviceId(), commandHandler, null, span.context()));
    } else {
        return tokenTracker.compose(v -> getCommandConsumerFactory().createCommandConsumer(sourceAddress.getTenantId(), sourceAddress.getResourceId(), commandHandler, null, span.context()));
    }
}
Also used : HttpURLConnection(java.net.HttpURLConnection) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonReceiver(io.vertx.proton.ProtonReceiver) LifecycleChange(org.eclipse.hono.notification.deviceregistry.LifecycleChange) DeviceChangeNotification(org.eclipse.hono.notification.deviceregistry.DeviceChangeNotification) Tags(io.opentracing.tag.Tags) ProtonServer(io.vertx.proton.ProtonServer) HonoProtonHelper(org.eclipse.hono.util.HonoProtonHelper) ProcessingOutcome(org.eclipse.hono.service.metric.MetricsTags.ProcessingOutcome) EndpointType(org.eclipse.hono.service.metric.MetricsTags.EndpointType) Modified(org.apache.qpid.proton.amqp.messaging.Modified) DeviceCredentials(org.eclipse.hono.adapter.auth.device.DeviceCredentials) Map(java.util.Map) DeliveryState(org.apache.qpid.proton.amqp.transport.DeliveryState) AuthorizationException(org.eclipse.hono.adapter.AuthorizationException) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) Fields(io.opentracing.log.Fields) AmqpError(org.apache.qpid.proton.amqp.transport.AmqpError) TracingHelper(org.eclipse.hono.tracing.TracingHelper) ProtonSaslAuthenticatorFactory(io.vertx.proton.sasl.ProtonSaslAuthenticatorFactory) AllDevicesOfTenantDeletedNotification(org.eclipse.hono.notification.deviceregistry.AllDevicesOfTenantDeletedNotification) TenantServiceBasedX509Authentication(org.eclipse.hono.adapter.auth.device.TenantServiceBasedX509Authentication) Predicate(java.util.function.Predicate) Collection(java.util.Collection) CommandContext(org.eclipse.hono.client.command.CommandContext) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) ProtonQoS(io.vertx.proton.ProtonQoS) MessageHelper(org.eclipse.hono.util.MessageHelper) Collectors(java.util.stream.Collectors) Future(io.vertx.core.Future) Device(org.eclipse.hono.auth.Device) Objects(java.util.Objects) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) List(java.util.List) QoS(org.eclipse.hono.service.metric.MetricsTags.QoS) TenantTraceSamplingHelper(org.eclipse.hono.tracing.TenantTraceSamplingHelper) CommandConsumer(org.eclipse.hono.client.command.CommandConsumer) Optional(java.util.Optional) Span(io.opentracing.Span) ProtonSender(io.vertx.proton.ProtonSender) NotificationEventBusSupport(org.eclipse.hono.notification.NotificationEventBusSupport) ProtonLink(io.vertx.proton.ProtonLink) Accepted(org.apache.qpid.proton.amqp.messaging.Accepted) ProtonServerOptions(io.vertx.proton.ProtonServerOptions) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) ConnectionLimitManager(org.eclipse.hono.adapter.limiting.ConnectionLimitManager) Command(org.eclipse.hono.client.command.Command) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) ClientErrorException(org.eclipse.hono.client.ClientErrorException) AdapterDisabledException(org.eclipse.hono.adapter.AdapterDisabledException) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) OptionalInt(java.util.OptionalInt) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) Commands(org.eclipse.hono.client.command.Commands) Constants(org.eclipse.hono.util.Constants) CompositeFuture(io.vertx.core.CompositeFuture) ProtonSession(io.vertx.proton.ProtonSession) Symbol(org.apache.qpid.proton.amqp.Symbol) AdapterConnectionsExceededException(org.eclipse.hono.adapter.AdapterConnectionsExceededException) Target(org.apache.qpid.proton.amqp.transport.Target) UnsignedLong(org.apache.qpid.proton.amqp.UnsignedLong) Message(org.apache.qpid.proton.message.Message) HttpUtils(org.eclipse.hono.service.http.HttpUtils) AsyncResult(io.vertx.core.AsyncResult) CommandConstants(org.eclipse.hono.util.CommandConstants) TenantChangeNotification(org.eclipse.hono.notification.deviceregistry.TenantChangeNotification) Strings(org.eclipse.hono.util.Strings) UsernamePasswordAuthProvider(org.eclipse.hono.adapter.auth.device.UsernamePasswordAuthProvider) CredentialsApiAuthProvider(org.eclipse.hono.adapter.auth.device.CredentialsApiAuthProvider) AbstractProtocolAdapterBase(org.eclipse.hono.adapter.AbstractProtocolAdapterBase) Direction(org.eclipse.hono.service.metric.MetricsTags.Direction) Promise(io.vertx.core.Promise) ServerErrorException(org.eclipse.hono.client.ServerErrorException) ProtonHelper(io.vertx.proton.ProtonHelper) Sample(io.micrometer.core.instrument.Timer.Sample) Released(org.apache.qpid.proton.amqp.messaging.Released) CommandResponse(org.eclipse.hono.client.command.CommandResponse) TenantObject(org.eclipse.hono.util.TenantObject) SpanContext(io.opentracing.SpanContext) Source(org.apache.qpid.proton.amqp.transport.Source) ConnectionAttemptOutcome(org.eclipse.hono.service.metric.MetricsTags.ConnectionAttemptOutcome) MemoryBasedConnectionLimitStrategy(org.eclipse.hono.adapter.limiting.MemoryBasedConnectionLimitStrategy) X509AuthProvider(org.eclipse.hono.adapter.auth.device.X509AuthProvider) Handler(io.vertx.core.Handler) Collections(java.util.Collections) DefaultConnectionLimitManager(org.eclipse.hono.adapter.limiting.DefaultConnectionLimitManager) CommandContext(org.eclipse.hono.client.command.CommandContext) Command(org.eclipse.hono.client.command.Command) Sample(io.micrometer.core.instrument.Timer.Sample) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) Future(io.vertx.core.Future) CompositeFuture(io.vertx.core.CompositeFuture) ClientErrorException(org.eclipse.hono.client.ClientErrorException) ServerErrorException(org.eclipse.hono.client.ServerErrorException)

Example 99 with Future

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

the class AbstractHonoResource method doUploadMessage.

/**
 * Forwards a message to the south bound Telemetry or Event API of the messaging infrastructure configured
 * for the tenant that the origin device belongs to.
 * <p>
 * Depending on the outcome of the attempt to upload the message, the CoAP response code is set as
 * described by the <a href="https://www.eclipse.org/hono/docs/user-guide/coap-adapter/">CoAP adapter user guide</a>
 *
 * @param context The request that contains the uploaded message.
 * @param endpoint The type of API endpoint to forward the message to.
 * @return A future indicating the outcome of the operation.
 *         The future will be succeeded if the message has been forwarded successfully.
 *         In this case one of the context's <em>respond</em> methods will have been invoked to send a CoAP response
 *         back to the device.
 *         Otherwise the future will be failed with a {@link org.eclipse.hono.client.ServiceInvocationException}.
 * @throws NullPointerException if any of the parameters are {@code null}.
 */
protected final Future<Void> doUploadMessage(final CoapContext context, final MetricsTags.EndpointType endpoint) {
    Objects.requireNonNull(context);
    Objects.requireNonNull(endpoint);
    final String contentType = context.getContentType();
    final Buffer payload = context.getPayload();
    if (contentType == null) {
        return Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "request message must contain content-format option"));
    } else if (payload.length() == 0 && !context.isEmptyNotification()) {
        return Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "request contains no body but is not marked as empty notification"));
    } else {
        final String gatewayId = context.getGatewayId();
        final String tenantId = context.getOriginDevice().getTenantId();
        final String deviceId = context.getOriginDevice().getDeviceId();
        final MetricsTags.QoS qos = context.isConfirmable() ? MetricsTags.QoS.AT_LEAST_ONCE : MetricsTags.QoS.AT_MOST_ONCE;
        final Span currentSpan = TracingHelper.buildChildSpan(getTracer(), context.getTracingContext(), "upload " + endpoint.getCanonicalName(), getAdapter().getTypeName()).withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT).withTag(TracingHelper.TAG_TENANT_ID, tenantId).withTag(TracingHelper.TAG_DEVICE_ID, deviceId).withTag(TracingHelper.TAG_AUTHENTICATED.getKey(), context.isDeviceAuthenticated()).withTag(Constants.HEADER_QOS_LEVEL, qos.asTag().getValue()).start();
        final Promise<Void> responseReady = Promise.promise();
        final Future<RegistrationAssertion> tokenTracker = getAdapter().getRegistrationAssertion(tenantId, deviceId, context.getAuthenticatedDevice(), currentSpan.context());
        final Future<TenantObject> tenantTracker = getAdapter().getTenantClient().get(tenantId, currentSpan.context());
        final Future<TenantObject> tenantValidationTracker = tenantTracker.compose(tenantObject -> CompositeFuture.all(getAdapter().isAdapterEnabled(tenantObject), getAdapter().checkMessageLimit(tenantObject, payload.length(), currentSpan.context())).map(tenantObject));
        // we only need to consider TTD if the device and tenant are enabled and the adapter
        // is enabled for the tenant
        final Future<Integer> ttdTracker = CompositeFuture.all(tenantValidationTracker, tokenTracker).compose(ok -> {
            final Integer ttdParam = context.getTimeUntilDisconnect();
            return getAdapter().getTimeUntilDisconnect(tenantTracker.result(), ttdParam).map(effectiveTtd -> {
                if (effectiveTtd != null) {
                    currentSpan.setTag(MessageHelper.APP_PROPERTY_DEVICE_TTD, effectiveTtd);
                }
                return effectiveTtd;
            });
        });
        final Future<CommandConsumer> commandConsumerTracker = ttdTracker.compose(ttd -> createCommandConsumer(ttd, tenantTracker.result(), deviceId, gatewayId, context, responseReady, currentSpan));
        return commandConsumerTracker.compose(commandConsumer -> {
            final Map<String, Object> props = getAdapter().getDownstreamMessageProperties(context);
            Optional.ofNullable(commandConsumer).map(c -> ttdTracker.result()).ifPresent(ttd -> props.put(MessageHelper.APP_PROPERTY_DEVICE_TTD, ttd));
            customizeDownstreamMessageProperties(props, context);
            if (context.isConfirmable()) {
                context.startAcceptTimer(vertx, tenantTracker.result(), getAdapter().getConfig().getTimeoutToAck());
            }
            final Future<Void> sendResult;
            if (endpoint == EndpointType.EVENT) {
                sendResult = getAdapter().getEventSender(tenantValidationTracker.result()).sendEvent(tenantTracker.result(), tokenTracker.result(), contentType, payload, props, currentSpan.context());
            } else {
                sendResult = getAdapter().getTelemetrySender(tenantValidationTracker.result()).sendTelemetry(tenantTracker.result(), tokenTracker.result(), context.getRequestedQos(), contentType, payload, props, currentSpan.context());
            }
            return CompositeFuture.all(sendResult, responseReady.future()).mapEmpty();
        }).compose(proceed -> {
            // request and the CommandConsumer from the current request has not been closed yet
            return Optional.ofNullable(commandConsumerTracker.result()).map(consumer -> consumer.close(currentSpan.context()).otherwise(thr -> {
                TracingHelper.logError(currentSpan, thr);
                return (Void) null;
            })).orElseGet(Future::succeededFuture);
        }).map(proceed -> {
            final CommandContext commandContext = context.get(CommandContext.KEY_COMMAND_CONTEXT);
            final Response response = new Response(ResponseCode.CHANGED);
            if (commandContext != null) {
                addCommandToResponse(response, commandContext, currentSpan);
                commandContext.accept();
                getAdapter().getMetrics().reportCommand(commandContext.getCommand().isOneWay() ? Direction.ONE_WAY : Direction.REQUEST, tenantId, tenantTracker.result(), ProcessingOutcome.FORWARDED, commandContext.getCommand().getPayloadSize(), getMicrometerSample(commandContext));
            }
            LOG.trace("successfully processed message for device [tenantId: {}, deviceId: {}, endpoint: {}]", tenantId, deviceId, endpoint.getCanonicalName());
            getAdapter().getMetrics().reportTelemetry(endpoint, tenantId, tenantTracker.result(), MetricsTags.ProcessingOutcome.FORWARDED, qos, payload.length(), getTtdStatus(context), context.getTimer());
            context.respond(response);
            currentSpan.finish();
            return (Void) null;
        }).recover(t -> {
            LOG.debug("cannot process message from device [tenantId: {}, deviceId: {}, endpoint: {}]", tenantId, deviceId, endpoint.getCanonicalName(), t);
            final Future<Void> commandConsumerClosedTracker = Optional.ofNullable(commandConsumerTracker.result()).map(consumer -> consumer.close(currentSpan.context()).onFailure(thr -> TracingHelper.logError(currentSpan, thr))).orElseGet(Future::succeededFuture);
            final CommandContext commandContext = context.get(CommandContext.KEY_COMMAND_CONTEXT);
            if (commandContext != null) {
                TracingHelper.logError(commandContext.getTracingSpan(), "command won't be forwarded to device in CoAP response, CoAP request handling failed", t);
                commandContext.release(t);
                currentSpan.log("released command for device");
            }
            getAdapter().getMetrics().reportTelemetry(endpoint, tenantId, tenantTracker.result(), ClientErrorException.class.isInstance(t) ? MetricsTags.ProcessingOutcome.UNPROCESSABLE : MetricsTags.ProcessingOutcome.UNDELIVERABLE, qos, payload.length(), getTtdStatus(context), context.getTimer());
            TracingHelper.logError(currentSpan, t);
            commandConsumerClosedTracker.onComplete(res -> currentSpan.finish());
            return Future.failedFuture(t);
        });
    }
}
Also used : Buffer(io.vertx.core.buffer.Buffer) HttpURLConnection(java.net.HttpURLConnection) ResponseCode(org.eclipse.californium.core.coap.CoAP.ResponseCode) CoapExchange(org.eclipse.californium.core.server.resources.CoapExchange) Response(org.eclipse.californium.core.coap.Response) Command(org.eclipse.hono.client.command.Command) LoggerFactory(org.slf4j.LoggerFactory) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ClientErrorException(org.eclipse.hono.client.ClientErrorException) Constants(org.eclipse.hono.util.Constants) Tags(io.opentracing.tag.Tags) ProcessingOutcome(org.eclipse.hono.service.metric.MetricsTags.ProcessingOutcome) CompositeFuture(io.vertx.core.CompositeFuture) EndpointType(org.eclipse.hono.service.metric.MetricsTags.EndpointType) TtdStatus(org.eclipse.hono.service.metric.MetricsTags.TtdStatus) References(io.opentracing.References) Duration(java.time.Duration) Map(java.util.Map) MediaTypeRegistry(org.eclipse.californium.core.coap.MediaTypeRegistry) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) TracingHelper(org.eclipse.hono.tracing.TracingHelper) AsyncResult(io.vertx.core.AsyncResult) CommandConstants(org.eclipse.hono.util.CommandConstants) Logger(org.slf4j.Logger) Tracer(io.opentracing.Tracer) Direction(org.eclipse.hono.service.metric.MetricsTags.Direction) Promise(io.vertx.core.Promise) CommandContext(org.eclipse.hono.client.command.CommandContext) MetricsTags(org.eclipse.hono.service.metric.MetricsTags) Vertx(io.vertx.core.Vertx) ServerErrorException(org.eclipse.hono.client.ServerErrorException) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) MessageHelper(org.eclipse.hono.util.MessageHelper) Sample(io.micrometer.core.instrument.Timer.Sample) Future(io.vertx.core.Future) Device(org.eclipse.hono.auth.Device) TenantObject(org.eclipse.hono.util.TenantObject) SpanContext(io.opentracing.SpanContext) Objects(java.util.Objects) List(java.util.List) Principal(java.security.Principal) Buffer(io.vertx.core.buffer.Buffer) CommandConsumer(org.eclipse.hono.client.command.CommandConsumer) Optional(java.util.Optional) Span(io.opentracing.Span) OptionSet(org.eclipse.californium.core.coap.OptionSet) Handler(io.vertx.core.Handler) CommandContext(org.eclipse.hono.client.command.CommandContext) Span(io.opentracing.Span) Response(org.eclipse.californium.core.coap.Response) Promise(io.vertx.core.Promise) ClientErrorException(org.eclipse.hono.client.ClientErrorException) CompositeFuture(io.vertx.core.CompositeFuture) Future(io.vertx.core.Future) TenantObject(org.eclipse.hono.util.TenantObject)

Example 100 with Future

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

the class VertxBasedAmqpProtocolAdapter method openCommandSenderLink.

private Future<CommandConsumer> openCommandSenderLink(final ProtonConnection connection, final ProtonSender sender, final ResourceIdentifier address, final Device authenticatedDevice, final Span span, final OptionalInt traceSamplingPriority) {
    return createCommandConsumer(sender, address, authenticatedDevice, span).map(consumer -> {
        final String tenantId = address.getTenantId();
        final String deviceId = address.getResourceId();
        sender.setSource(sender.getRemoteSource());
        sender.setTarget(sender.getRemoteTarget());
        sender.setQoS(ProtonQoS.AT_LEAST_ONCE);
        final Handler<AsyncResult<ProtonSender>> detachHandler = link -> {
            final Span detachHandlerSpan = newSpan("detach device command receiver link", authenticatedDevice, traceSamplingPriority);
            removeCommandSubscription(connection, address.toString());
            onLinkDetach(sender);
            closeCommandConsumer(consumer, address, authenticatedDevice, true, detachHandlerSpan).onComplete(v -> detachHandlerSpan.finish());
        };
        HonoProtonHelper.setCloseHandler(sender, detachHandler);
        HonoProtonHelper.setDetachHandler(sender, detachHandler);
        sender.open();
        // At this point, the remote peer's receiver link is successfully opened and is ready to receive
        // commands. Send "device ready for command" notification downstream.
        log.debug("established link [address: {}] for sending commands to device", address);
        sendConnectedTtdEvent(tenantId, deviceId, authenticatedDevice, span.context());
        registerCommandSubscription(connection, new CommandSubscription(consumer, address));
        return consumer;
    }).recover(t -> Future.failedFuture(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "cannot create command consumer")));
}
Also used : HttpURLConnection(java.net.HttpURLConnection) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonReceiver(io.vertx.proton.ProtonReceiver) LifecycleChange(org.eclipse.hono.notification.deviceregistry.LifecycleChange) DeviceChangeNotification(org.eclipse.hono.notification.deviceregistry.DeviceChangeNotification) Tags(io.opentracing.tag.Tags) ProtonServer(io.vertx.proton.ProtonServer) HonoProtonHelper(org.eclipse.hono.util.HonoProtonHelper) ProcessingOutcome(org.eclipse.hono.service.metric.MetricsTags.ProcessingOutcome) EndpointType(org.eclipse.hono.service.metric.MetricsTags.EndpointType) Modified(org.apache.qpid.proton.amqp.messaging.Modified) DeviceCredentials(org.eclipse.hono.adapter.auth.device.DeviceCredentials) Map(java.util.Map) DeliveryState(org.apache.qpid.proton.amqp.transport.DeliveryState) AuthorizationException(org.eclipse.hono.adapter.AuthorizationException) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) Fields(io.opentracing.log.Fields) AmqpError(org.apache.qpid.proton.amqp.transport.AmqpError) TracingHelper(org.eclipse.hono.tracing.TracingHelper) ProtonSaslAuthenticatorFactory(io.vertx.proton.sasl.ProtonSaslAuthenticatorFactory) AllDevicesOfTenantDeletedNotification(org.eclipse.hono.notification.deviceregistry.AllDevicesOfTenantDeletedNotification) TenantServiceBasedX509Authentication(org.eclipse.hono.adapter.auth.device.TenantServiceBasedX509Authentication) Predicate(java.util.function.Predicate) Collection(java.util.Collection) CommandContext(org.eclipse.hono.client.command.CommandContext) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) ProtonQoS(io.vertx.proton.ProtonQoS) MessageHelper(org.eclipse.hono.util.MessageHelper) Collectors(java.util.stream.Collectors) Future(io.vertx.core.Future) Device(org.eclipse.hono.auth.Device) Objects(java.util.Objects) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) List(java.util.List) QoS(org.eclipse.hono.service.metric.MetricsTags.QoS) TenantTraceSamplingHelper(org.eclipse.hono.tracing.TenantTraceSamplingHelper) CommandConsumer(org.eclipse.hono.client.command.CommandConsumer) Optional(java.util.Optional) Span(io.opentracing.Span) ProtonSender(io.vertx.proton.ProtonSender) NotificationEventBusSupport(org.eclipse.hono.notification.NotificationEventBusSupport) ProtonLink(io.vertx.proton.ProtonLink) Accepted(org.apache.qpid.proton.amqp.messaging.Accepted) ProtonServerOptions(io.vertx.proton.ProtonServerOptions) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) ConnectionLimitManager(org.eclipse.hono.adapter.limiting.ConnectionLimitManager) Command(org.eclipse.hono.client.command.Command) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) ClientErrorException(org.eclipse.hono.client.ClientErrorException) AdapterDisabledException(org.eclipse.hono.adapter.AdapterDisabledException) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) OptionalInt(java.util.OptionalInt) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) Commands(org.eclipse.hono.client.command.Commands) Constants(org.eclipse.hono.util.Constants) CompositeFuture(io.vertx.core.CompositeFuture) ProtonSession(io.vertx.proton.ProtonSession) Symbol(org.apache.qpid.proton.amqp.Symbol) AdapterConnectionsExceededException(org.eclipse.hono.adapter.AdapterConnectionsExceededException) Target(org.apache.qpid.proton.amqp.transport.Target) UnsignedLong(org.apache.qpid.proton.amqp.UnsignedLong) Message(org.apache.qpid.proton.message.Message) HttpUtils(org.eclipse.hono.service.http.HttpUtils) AsyncResult(io.vertx.core.AsyncResult) CommandConstants(org.eclipse.hono.util.CommandConstants) TenantChangeNotification(org.eclipse.hono.notification.deviceregistry.TenantChangeNotification) Strings(org.eclipse.hono.util.Strings) UsernamePasswordAuthProvider(org.eclipse.hono.adapter.auth.device.UsernamePasswordAuthProvider) CredentialsApiAuthProvider(org.eclipse.hono.adapter.auth.device.CredentialsApiAuthProvider) AbstractProtocolAdapterBase(org.eclipse.hono.adapter.AbstractProtocolAdapterBase) Direction(org.eclipse.hono.service.metric.MetricsTags.Direction) Promise(io.vertx.core.Promise) ServerErrorException(org.eclipse.hono.client.ServerErrorException) ProtonHelper(io.vertx.proton.ProtonHelper) Sample(io.micrometer.core.instrument.Timer.Sample) Released(org.apache.qpid.proton.amqp.messaging.Released) CommandResponse(org.eclipse.hono.client.command.CommandResponse) TenantObject(org.eclipse.hono.util.TenantObject) SpanContext(io.opentracing.SpanContext) Source(org.apache.qpid.proton.amqp.transport.Source) ConnectionAttemptOutcome(org.eclipse.hono.service.metric.MetricsTags.ConnectionAttemptOutcome) MemoryBasedConnectionLimitStrategy(org.eclipse.hono.adapter.limiting.MemoryBasedConnectionLimitStrategy) X509AuthProvider(org.eclipse.hono.adapter.auth.device.X509AuthProvider) Handler(io.vertx.core.Handler) Collections(java.util.Collections) DefaultConnectionLimitManager(org.eclipse.hono.adapter.limiting.DefaultConnectionLimitManager) ProtonSender(io.vertx.proton.ProtonSender) Handler(io.vertx.core.Handler) ServerErrorException(org.eclipse.hono.client.ServerErrorException) Span(io.opentracing.Span)

Aggregations

Future (io.vertx.core.Future)370 HttpURLConnection (java.net.HttpURLConnection)195 Handler (io.vertx.core.Handler)174 List (java.util.List)166 Objects (java.util.Objects)164 JsonObject (io.vertx.core.json.JsonObject)163 Promise (io.vertx.core.Promise)160 Vertx (io.vertx.core.Vertx)157 Buffer (io.vertx.core.buffer.Buffer)149 Optional (java.util.Optional)147 Logger (org.slf4j.Logger)136 LoggerFactory (org.slf4j.LoggerFactory)136 CompositeFuture (io.vertx.core.CompositeFuture)127 ClientErrorException (org.eclipse.hono.client.ClientErrorException)127 Map (java.util.Map)122 Span (io.opentracing.Span)117 AsyncResult (io.vertx.core.AsyncResult)112 TracingHelper (org.eclipse.hono.tracing.TracingHelper)98 Constants (org.eclipse.hono.util.Constants)97 ArrayList (java.util.ArrayList)94