Search in sources :

Example 6 with CommandResponse

use of org.eclipse.hono.client.command.CommandResponse in project hono by eclipse.

the class AbstractVertxBasedMqttProtocolAdapter method uploadCommandResponseMessage.

/**
 * Uploads a command response message.
 *
 * @param ctx The context in which the MQTT message has been published.
 * @param targetAddress The address that the response should be forwarded to.
 * @return A future indicating the outcome of the operation.
 *         <p>
 *         The future will succeed if the message has been uploaded successfully.
 *         Otherwise, the future will fail with a {@link ServiceInvocationException}.
 * @throws NullPointerException if any of the parameters are {@code null}.
 */
public final Future<Void> uploadCommandResponseMessage(final MqttContext ctx, final ResourceIdentifier targetAddress) {
    Objects.requireNonNull(ctx);
    Objects.requireNonNull(targetAddress);
    final String[] addressPath = targetAddress.getResourcePath();
    Integer status = null;
    String reqId = null;
    final Future<CommandResponse> commandResponseTracker;
    if (addressPath.length <= CommandConstants.TOPIC_POSITION_RESPONSE_STATUS) {
        commandResponseTracker = Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "command response topic has too few segments"));
    } else {
        try {
            status = Integer.parseInt(addressPath[CommandConstants.TOPIC_POSITION_RESPONSE_STATUS]);
        } catch (final NumberFormatException e) {
            log.trace("got invalid status code [{}] [tenant-id: {}, device-id: {}]", addressPath[CommandConstants.TOPIC_POSITION_RESPONSE_STATUS], targetAddress.getTenantId(), targetAddress.getResourceId());
        }
        if (status != null) {
            reqId = addressPath[CommandConstants.TOPIC_POSITION_RESPONSE_REQ_ID];
            final CommandResponse commandResponse = CommandResponse.fromRequestId(reqId, targetAddress.getTenantId(), targetAddress.getResourceId(), ctx.message().payload(), ctx.contentType(), status);
            commandResponseTracker = commandResponse != null ? Future.succeededFuture(commandResponse) : Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "command response topic contains invalid data"));
        } else {
            // status code could not be parsed
            commandResponseTracker = Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "invalid status code"));
        }
    }
    final Span currentSpan = TracingHelper.buildChildSpan(tracer, ctx.getTracingContext(), "upload Command response", getTypeName()).withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT).withTag(TracingHelper.TAG_TENANT_ID, targetAddress.getTenantId()).withTag(TracingHelper.TAG_DEVICE_ID, targetAddress.getResourceId()).withTag(Constants.HEADER_COMMAND_RESPONSE_STATUS, status).withTag(Constants.HEADER_COMMAND_REQUEST_ID, reqId).withTag(TracingHelper.TAG_AUTHENTICATED.getKey(), ctx.authenticatedDevice() != null).start();
    final int payloadSize = Optional.ofNullable(ctx.message().payload()).map(Buffer::length).orElse(0);
    final Future<TenantObject> tenantTracker = getTenantConfiguration(targetAddress.getTenantId(), ctx.getTracingContext());
    return CompositeFuture.all(tenantTracker, commandResponseTracker).compose(success -> {
        final Future<RegistrationAssertion> deviceRegistrationTracker = getRegistrationAssertion(targetAddress.getTenantId(), targetAddress.getResourceId(), ctx.authenticatedDevice(), currentSpan.context());
        final Future<Void> tenantValidationTracker = CompositeFuture.all(isAdapterEnabled(tenantTracker.result()), checkMessageLimit(tenantTracker.result(), payloadSize, currentSpan.context())).mapEmpty();
        return CompositeFuture.all(deviceRegistrationTracker, tenantValidationTracker).compose(ok -> sendCommandResponse(tenantTracker.result(), deviceRegistrationTracker.result(), commandResponseTracker.result(), currentSpan.context()));
    }).compose(delivery -> {
        log.trace("successfully forwarded command response from device [tenant-id: {}, device-id: {}]", targetAddress.getTenantId(), targetAddress.getResourceId());
        metrics.reportCommand(Direction.RESPONSE, targetAddress.getTenantId(), tenantTracker.result(), ProcessingOutcome.FORWARDED, payloadSize, ctx.getTimer());
        // check that the remote MQTT client is still connected before sending PUBACK
        if (ctx.isAtLeastOnce() && ctx.deviceEndpoint().isConnected()) {
            currentSpan.log(EVENT_SENDING_PUBACK);
            ctx.acknowledge();
        }
        currentSpan.finish();
        return Future.<Void>succeededFuture();
    }).recover(t -> {
        TracingHelper.logError(currentSpan, t);
        currentSpan.finish();
        metrics.reportCommand(Direction.RESPONSE, targetAddress.getTenantId(), tenantTracker.result(), ProcessingOutcome.from(t), payloadSize, ctx.getTimer());
        return Future.failedFuture(t);
    });
}
Also used : HttpURLConnection(java.net.HttpURLConnection) LifecycleChange(org.eclipse.hono.notification.deviceregistry.LifecycleChange) ZonedDateTime(java.time.ZonedDateTime) DeviceChangeNotification(org.eclipse.hono.notification.deviceregistry.DeviceChangeNotification) MqttEndpoint(io.vertx.mqtt.MqttEndpoint) MqttPublishMessage(io.vertx.mqtt.messages.MqttPublishMessage) Tags(io.opentracing.tag.Tags) ProcessingOutcome(org.eclipse.hono.service.metric.MetricsTags.ProcessingOutcome) EndpointType(org.eclipse.hono.service.metric.MetricsTags.EndpointType) DeviceCredentials(org.eclipse.hono.adapter.auth.device.DeviceCredentials) Map(java.util.Map) Pair(org.eclipse.hono.util.Pair) AuthorizationException(org.eclipse.hono.adapter.AuthorizationException) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) Fields(io.opentracing.log.Fields) JsonObject(io.vertx.core.json.JsonObject) MqttConnectionException(io.vertx.mqtt.MqttConnectionException) ZoneOffset(java.time.ZoneOffset) TracingHelper(org.eclipse.hono.tracing.TracingHelper) AllDevicesOfTenantDeletedNotification(org.eclipse.hono.notification.deviceregistry.AllDevicesOfTenantDeletedNotification) AuthHandler(org.eclipse.hono.adapter.auth.device.AuthHandler) Futures(org.eclipse.hono.util.Futures) TenantServiceBasedX509Authentication(org.eclipse.hono.adapter.auth.device.TenantServiceBasedX509Authentication) Predicate(java.util.function.Predicate) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) CommandContext(org.eclipse.hono.client.command.CommandContext) MetricsTags(org.eclipse.hono.service.metric.MetricsTags) Set(java.util.Set) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) 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) List(java.util.List) TenantTraceSamplingHelper(org.eclipse.hono.tracing.TenantTraceSamplingHelper) Buffer(io.vertx.core.buffer.Buffer) CommandConsumer(org.eclipse.hono.client.command.CommandConsumer) Optional(java.util.Optional) Span(io.opentracing.Span) NotificationEventBusSupport(org.eclipse.hono.notification.NotificationEventBusSupport) MqttQoS(io.netty.handler.codec.mqtt.MqttQoS) MqttConnectReturnCode(io.netty.handler.codec.mqtt.MqttConnectReturnCode) 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) Deque(java.util.Deque) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) OptionalInt(java.util.OptionalInt) AtomicReference(java.util.concurrent.atomic.AtomicReference) Constants(org.eclipse.hono.util.Constants) ArrayList(java.util.ArrayList) DeviceUser(org.eclipse.hono.service.auth.DeviceUser) MqttServer(io.vertx.mqtt.MqttServer) HashSet(java.util.HashSet) CompositeFuture(io.vertx.core.CompositeFuture) SSLSession(javax.net.ssl.SSLSession) MqttTopicSubscription(io.vertx.mqtt.MqttTopicSubscription) AdapterConnectionsExceededException(org.eclipse.hono.adapter.AdapterConnectionsExceededException) LinkedList(java.util.LinkedList) CommandConstants(org.eclipse.hono.util.CommandConstants) TenantChangeNotification(org.eclipse.hono.notification.deviceregistry.TenantChangeNotification) ChainAuthHandler(org.eclipse.hono.adapter.auth.device.ChainAuthHandler) 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) MqttServerOptions(io.vertx.mqtt.MqttServerOptions) Promise(io.vertx.core.Promise) MqttSubscribeMessage(io.vertx.mqtt.messages.MqttSubscribeMessage) ServerErrorException(org.eclipse.hono.client.ServerErrorException) Sample(io.micrometer.core.instrument.Timer.Sample) CommandResponse(org.eclipse.hono.client.command.CommandResponse) TenantObject(org.eclipse.hono.util.TenantObject) SpanContext(io.opentracing.SpanContext) ErrorHandlingMode(org.eclipse.hono.adapter.mqtt.MqttContext.ErrorHandlingMode) MqttUnsubscribeMessage(io.vertx.mqtt.messages.MqttUnsubscribeMessage) ChronoUnit(java.time.temporal.ChronoUnit) ConnectionAttemptOutcome(org.eclipse.hono.service.metric.MetricsTags.ConnectionAttemptOutcome) MemoryBasedConnectionLimitStrategy(org.eclipse.hono.adapter.limiting.MemoryBasedConnectionLimitStrategy) X509AuthProvider(org.eclipse.hono.adapter.auth.device.X509AuthProvider) DateTimeFormatter(java.time.format.DateTimeFormatter) ArrayDeque(java.util.ArrayDeque) Handler(io.vertx.core.Handler) DefaultConnectionLimitManager(org.eclipse.hono.adapter.limiting.DefaultConnectionLimitManager) CommandResponse(org.eclipse.hono.client.command.CommandResponse) Span(io.opentracing.Span) MqttEndpoint(io.vertx.mqtt.MqttEndpoint) TenantObject(org.eclipse.hono.util.TenantObject) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) ClientErrorException(org.eclipse.hono.client.ClientErrorException)

Example 7 with CommandResponse

use of org.eclipse.hono.client.command.CommandResponse in project hono by eclipse.

the class KafkaBasedCommandResponseSenderTest method testIfValidCommandResponseKafkaRecordIsSent.

@Test
void testIfValidCommandResponseKafkaRecordIsSent(final VertxTestContext ctx, final Vertx vertx) {
    // GIVEN a command response sender
    final String tenantId = "test-tenant";
    final String deviceId = "test-device";
    final String correlationId = UUID.randomUUID().toString();
    final String contentType = "text/plain";
    final String payload = "the-payload";
    final int status = 200;
    final String additionalHeader1Name = "testHeader1";
    final String additionalHeader1Value = "testHeader1Value";
    final String additionalHeader2Name = "testHeader2";
    final String additionalHeader2Value = "testHeader2Value";
    final Map<String, Object> additionalProperties = Map.of(additionalHeader1Name, additionalHeader1Value, additionalHeader2Name, additionalHeader2Value);
    final CommandResponse commandResponse = CommandResponse.fromAddressAndCorrelationId(String.format("%s/%s/%s", CommandConstants.COMMAND_RESPONSE_ENDPOINT, tenantId, Commands.getDeviceFacingReplyToId("", deviceId, MessagingType.kafka)), correlationId, Buffer.buffer(payload), contentType, status);
    commandResponse.setAdditionalProperties(additionalProperties);
    final Span span = TracingMockSupport.mockSpan();
    final Tracer tracer = TracingMockSupport.mockTracer(span);
    final var mockProducer = KafkaClientUnitTestHelper.newMockProducer(true);
    final var factory = CachingKafkaProducerFactory.testFactory(vertx, (n, c) -> KafkaClientUnitTestHelper.newKafkaProducer(mockProducer));
    final var sender = new KafkaBasedCommandResponseSender(vertx, factory, kafkaProducerConfig, tracer);
    final TenantObject tenant = TenantObject.from(tenantId);
    tenant.setResourceLimits(new ResourceLimits().setMaxTtlCommandResponse(10L));
    // WHEN sending a command response
    sender.sendCommandResponse(tenant, new RegistrationAssertion(deviceId), commandResponse, NoopSpan.INSTANCE.context()).onComplete(ctx.succeeding(t -> {
        ctx.verify(() -> {
            // THEN the producer record is created from the given values...
            final ProducerRecord<String, Buffer> record = mockProducer.history().get(0);
            assertThat(record.key()).isEqualTo(deviceId);
            assertThat(record.topic()).isEqualTo(new HonoTopic(HonoTopic.Type.COMMAND_RESPONSE, tenantId).toString());
            assertThat(record.value().toString()).isEqualTo(payload);
            // Verify if the record contains the necessary headers.
            final Headers headers = record.headers();
            KafkaClientUnitTestHelper.assertUniqueHeaderWithExpectedValue(headers, MessageHelper.APP_PROPERTY_TENANT_ID, tenantId);
            KafkaClientUnitTestHelper.assertUniqueHeaderWithExpectedValue(headers, MessageHelper.APP_PROPERTY_DEVICE_ID, deviceId);
            KafkaClientUnitTestHelper.assertUniqueHeaderWithExpectedValue(headers, MessageHelper.SYS_PROPERTY_CORRELATION_ID, correlationId);
            KafkaClientUnitTestHelper.assertUniqueHeaderWithExpectedValue(headers, MessageHelper.APP_PROPERTY_STATUS, status);
            KafkaClientUnitTestHelper.assertUniqueHeaderWithExpectedValue(headers, MessageHelper.SYS_PROPERTY_CONTENT_TYPE, contentType);
            final var creationTimeHeader = headers.headers(MessageHelper.SYS_PROPERTY_CREATION_TIME);
            assertThat(creationTimeHeader).hasSize(1);
            final Long creationTimeMillis = Json.decodeValue(Buffer.buffer(creationTimeHeader.iterator().next().value()), Long.class);
            assertThat(creationTimeMillis).isGreaterThan(0L);
            KafkaClientUnitTestHelper.assertUniqueHeaderWithExpectedValue(headers, MessageHelper.SYS_HEADER_PROPERTY_TTL, 10000L);
            KafkaClientUnitTestHelper.assertUniqueHeaderWithExpectedValue(headers, additionalHeader1Name, additionalHeader1Value);
            KafkaClientUnitTestHelper.assertUniqueHeaderWithExpectedValue(headers, additionalHeader2Name, additionalHeader2Value);
            verify(span).finish();
        });
        ctx.completeNow();
    }));
}
Also used : VertxTestContext(io.vertx.junit5.VertxTestContext) BeforeEach(org.junit.jupiter.api.BeforeEach) Json(io.vertx.core.json.Json) ProducerRecord(org.apache.kafka.clients.producer.ProducerRecord) MessagingKafkaProducerConfigProperties(org.eclipse.hono.client.kafka.producer.MessagingKafkaProducerConfigProperties) ArgumentMatchers.eq(org.mockito.ArgumentMatchers.eq) Headers(org.apache.kafka.common.header.Headers) HashMap(java.util.HashMap) Commands(org.eclipse.hono.client.command.Commands) MessagingType(org.eclipse.hono.util.MessagingType) EventBus(io.vertx.core.eventbus.EventBus) ExtendWith(org.junit.jupiter.api.extension.ExtendWith) Mockito.verifyNoMoreInteractions(org.mockito.Mockito.verifyNoMoreInteractions) Map(java.util.Map) TracingMockSupport(org.eclipse.hono.test.TracingMockSupport) CommandConstants(org.eclipse.hono.util.CommandConstants) KafkaClientUnitTestHelper(org.eclipse.hono.kafka.test.KafkaClientUnitTestHelper) TenantChangeNotification(org.eclipse.hono.notification.deviceregistry.TenantChangeNotification) ResourceLimits(org.eclipse.hono.util.ResourceLimits) Tracer(io.opentracing.Tracer) CachingKafkaProducerFactory(org.eclipse.hono.client.kafka.producer.CachingKafkaProducerFactory) Vertx(io.vertx.core.Vertx) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) Mockito.when(org.mockito.Mockito.when) UUID(java.util.UUID) Truth.assertThat(com.google.common.truth.Truth.assertThat) MessageHelper(org.eclipse.hono.util.MessageHelper) VertxExtension(io.vertx.junit5.VertxExtension) Mockito.verify(org.mockito.Mockito.verify) CommandResponse(org.eclipse.hono.client.command.CommandResponse) TenantObject(org.eclipse.hono.util.TenantObject) Test(org.junit.jupiter.api.Test) HonoTopic(org.eclipse.hono.client.kafka.HonoTopic) Buffer(io.vertx.core.buffer.Buffer) VertxMockSupport(org.eclipse.hono.test.VertxMockSupport) Span(io.opentracing.Span) NotificationEventBusSupport(org.eclipse.hono.notification.NotificationEventBusSupport) NoopSpan(io.opentracing.noop.NoopSpan) Mockito.mock(org.mockito.Mockito.mock) Tracer(io.opentracing.Tracer) Headers(org.apache.kafka.common.header.Headers) CommandResponse(org.eclipse.hono.client.command.CommandResponse) HonoTopic(org.eclipse.hono.client.kafka.HonoTopic) Span(io.opentracing.Span) NoopSpan(io.opentracing.noop.NoopSpan) TenantObject(org.eclipse.hono.util.TenantObject) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) ResourceLimits(org.eclipse.hono.util.ResourceLimits) ProducerRecord(org.apache.kafka.clients.producer.ProducerRecord) TenantObject(org.eclipse.hono.util.TenantObject) Test(org.junit.jupiter.api.Test)

Example 8 with CommandResponse

use of org.eclipse.hono.client.command.CommandResponse in project hono by eclipse.

the class KafkaBasedCommandContext method sendDeliveryFailureCommandResponseMessage.

private Future<Void> sendDeliveryFailureCommandResponseMessage(final int status, final String error, final Span span, final Throwable cause) {
    final JsonObject payloadJson = new JsonObject();
    payloadJson.put("error", error != null ? error : "");
    final String correlationId = getCorrelationId();
    if (correlationId == null) {
        TracingHelper.logError(span, "can't send command response message - no correlation id set");
        return Future.failedFuture("missing correlation id");
    }
    final CommandResponse commandResponse = new CommandResponse(command.getTenant(), command.getDeviceId(), payloadJson.toBuffer(), CommandConstants.CONTENT_TYPE_DELIVERY_FAILURE_NOTIFICATION, status, correlationId, "", MessagingType.kafka);
    commandResponse.setAdditionalProperties(Collections.unmodifiableMap(command.getDeliveryFailureNotificationProperties()));
    return commandResponseSender.sendCommandResponse(// try to retrieve tenant configuration from context
    Optional.ofNullable(get(KEY_TENANT_CONFIG)).filter(TenantObject.class::isInstance).map(TenantObject.class::cast).orElseGet(() -> TenantObject.from(command.getTenant())), new RegistrationAssertion(command.getDeviceId()), commandResponse, span.context()).onFailure(thr -> {
        LOG.debug("failed to publish command response [{}]", commandResponse, thr);
        TracingHelper.logError(span, "failed to publish command response message", thr);
    }).onSuccess(v -> {
        LOG.debug("published error command response [{}, cause: {}]", commandResponse, cause != null ? cause.getMessage() : error);
        span.log("published error command response");
    });
}
Also used : HttpURLConnection(java.net.HttpURLConnection) LoggerFactory(org.slf4j.LoggerFactory) ClientErrorException(org.eclipse.hono.client.ClientErrorException) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) CommandResponseSender(org.eclipse.hono.client.command.CommandResponseSender) Tags(io.opentracing.tag.Tags) CommandAlreadyProcessedException(org.eclipse.hono.client.command.CommandAlreadyProcessedException) MessagingType(org.eclipse.hono.util.MessagingType) StatusCodeMapper(org.eclipse.hono.client.StatusCodeMapper) JsonObject(io.vertx.core.json.JsonObject) TracingHelper(org.eclipse.hono.tracing.TracingHelper) CommandConstants(org.eclipse.hono.util.CommandConstants) Logger(org.slf4j.Logger) CommandToBeReprocessedException(org.eclipse.hono.client.command.CommandToBeReprocessedException) CommandContext(org.eclipse.hono.client.command.CommandContext) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) KafkaRecordHelper(org.eclipse.hono.client.kafka.KafkaRecordHelper) Future(io.vertx.core.Future) CommandResponse(org.eclipse.hono.client.command.CommandResponse) TenantObject(org.eclipse.hono.util.TenantObject) Objects(java.util.Objects) MapBasedExecutionContext(org.eclipse.hono.util.MapBasedExecutionContext) Optional(java.util.Optional) Span(io.opentracing.Span) Collections(java.util.Collections) TenantObject(org.eclipse.hono.util.TenantObject) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) JsonObject(io.vertx.core.json.JsonObject) CommandResponse(org.eclipse.hono.client.command.CommandResponse)

Example 9 with CommandResponse

use of org.eclipse.hono.client.command.CommandResponse in project hono by eclipse.

the class ProtonBasedCommandResponseSenderTest method testCommandResponseMessageHasCreationTimeAndTtl.

/**
 * Verifies that command response messages being sent downstream contain a creation-time
 * and a time-to-live as defined at the tenant level.
 */
@Test
public void testCommandResponseMessageHasCreationTimeAndTtl() {
    final var now = Instant.now();
    final TenantObject tenant = TenantObject.from(TENANT_ID);
    tenant.setResourceLimits(new ResourceLimits().setMaxTtlCommandResponse(10L));
    when(protonSender.sendQueueFull()).thenReturn(Boolean.FALSE);
    when(protonSender.send(any(Message.class), VertxMockSupport.anyHandler())).thenReturn(mock(ProtonDelivery.class));
    // WHEN sending a command response message
    final CommandResponse commandResponse = CommandResponse.fromRequestId(Commands.encodeRequestIdParameters(CORRELATION_ID, REPLY_TO_ID, DEVICE_ID, MessagingType.amqp), TENANT_ID, DEVICE_ID, null, null, HttpURLConnection.HTTP_OK);
    sender.sendCommandResponse(tenant, new RegistrationAssertion(DEVICE_ID), commandResponse, span.context());
    final ArgumentCaptor<Message> downstreamMessage = ArgumentCaptor.forClass(Message.class);
    verify(protonSender).send(downstreamMessage.capture(), VertxMockSupport.anyHandler());
    // THEN the message being sent contains a creation-time
    assertThat(downstreamMessage.getValue().getCreationTime()).isAtLeast(now.toEpochMilli());
    // and a TTL
    assertThat(downstreamMessage.getValue().getTtl()).isEqualTo(10_000L);
    // and a 200 status code
    assertThat(MessageHelper.getStatus(downstreamMessage.getValue())).isEqualTo(HttpURLConnection.HTTP_OK);
}
Also used : TenantObject(org.eclipse.hono.util.TenantObject) Message(org.apache.qpid.proton.message.Message) ProtonDelivery(io.vertx.proton.ProtonDelivery) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) ResourceLimits(org.eclipse.hono.util.ResourceLimits) CommandResponse(org.eclipse.hono.client.command.CommandResponse) Test(org.junit.jupiter.api.Test)

Example 10 with CommandResponse

use of org.eclipse.hono.client.command.CommandResponse in project hono by eclipse.

the class VertxBasedAmqpProtocolAdapter method doUploadCommandResponseMessage.

private Future<Void> doUploadCommandResponseMessage(final AmqpContext context, final ResourceIdentifier resource, final Span currentSpan) {
    final Future<CommandResponse> responseTracker = Optional.ofNullable(getCommandResponse(context.getMessage())).map(Future::succeededFuture).orElseGet(() -> {
        TracingHelper.logError(currentSpan, String.format("invalid message (correlationId: %s, address: %s, status: %s)", context.getMessage().getCorrelationId(), context.getMessage().getAddress(), MessageHelper.getStatus(context.getMessage())));
        return Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "malformed command response message"));
    });
    final Future<TenantObject> tenantTracker = getTenantConfiguration(resource.getTenantId(), currentSpan.context());
    return CompositeFuture.all(tenantTracker, responseTracker).compose(ok -> {
        final CommandResponse commandResponse = responseTracker.result();
        log.trace("sending command response [device-id: {}, status: {}, correlation-id: {}, reply-to: {}]", resource.getResourceId(), commandResponse.getStatus(), commandResponse.getCorrelationId(), commandResponse.getReplyToId());
        final Map<String, Object> items = new HashMap<>(3);
        items.put(Fields.EVENT, "sending command response");
        items.put(TracingHelper.TAG_CORRELATION_ID.getKey(), commandResponse.getCorrelationId());
        items.put(MessageHelper.APP_PROPERTY_STATUS, commandResponse.getStatus());
        currentSpan.log(items);
        final Future<RegistrationAssertion> tokenFuture = getRegistrationAssertion(resource.getTenantId(), resource.getResourceId(), context.getAuthenticatedDevice(), currentSpan.context());
        final Future<TenantObject> tenantValidationTracker = CompositeFuture.all(isAdapterEnabled(tenantTracker.result()), checkMessageLimit(tenantTracker.result(), context.getPayloadSize(), currentSpan.context())).map(success -> tenantTracker.result());
        return CompositeFuture.all(tenantValidationTracker, tokenFuture).compose(success -> sendCommandResponse(tenantTracker.result(), tokenFuture.result(), commandResponse, currentSpan.context()));
    }).map(delivery -> {
        log.trace("forwarded command response from device [tenant: {}, device-id: {}]", resource.getTenantId(), resource.getResourceId());
        metrics.reportCommand(Direction.RESPONSE, resource.getTenantId(), tenantTracker.result(), ProcessingOutcome.FORWARDED, context.getPayloadSize(), context.getTimer());
        return delivery;
    }).recover(t -> {
        log.debug("cannot process command response from device [tenant: {}, device-id: {}]", resource.getTenantId(), resource.getResourceId(), t);
        metrics.reportCommand(Direction.RESPONSE, resource.getTenantId(), tenantTracker.result(), ProcessingOutcome.from(t), context.getPayloadSize(), context.getTimer());
        return Future.failedFuture(t);
    });
}
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) TenantObject(org.eclipse.hono.util.TenantObject) HashMap(java.util.HashMap) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) ClientErrorException(org.eclipse.hono.client.ClientErrorException) TenantObject(org.eclipse.hono.util.TenantObject) CommandResponse(org.eclipse.hono.client.command.CommandResponse)

Aggregations

CommandResponse (org.eclipse.hono.client.command.CommandResponse)11 RegistrationAssertion (org.eclipse.hono.util.RegistrationAssertion)11 TenantObject (org.eclipse.hono.util.TenantObject)11 Span (io.opentracing.Span)8 Future (io.vertx.core.Future)7 HttpURLConnection (java.net.HttpURLConnection)6 Objects (java.util.Objects)6 ClientErrorException (org.eclipse.hono.client.ClientErrorException)6 CommandConstants (org.eclipse.hono.util.CommandConstants)6 Tags (io.opentracing.tag.Tags)5 Optional (java.util.Optional)5 TracingHelper (org.eclipse.hono.tracing.TracingHelper)5 MessageHelper (org.eclipse.hono.util.MessageHelper)5 SpanContext (io.opentracing.SpanContext)4 CompositeFuture (io.vertx.core.CompositeFuture)4 Buffer (io.vertx.core.buffer.Buffer)4 Map (java.util.Map)4 Message (org.apache.qpid.proton.message.Message)4 Test (org.junit.jupiter.api.Test)4 Sample (io.micrometer.core.instrument.Timer.Sample)3