Search in sources :

Example 96 with Device

use of org.eclipse.hono.auth.Device in project hono by eclipse.

the class AbstractVertxBasedHttpProtocolAdapter method createCommandConsumer.

/**
 * Creates a consumer for command messages to be sent to a device.
 *
 * @param ttdSecs The number of seconds the device waits for a command.
 * @param tenantObject The tenant configuration object.
 * @param deviceId The identifier of the device.
 * @param gatewayId The identifier of the gateway that is acting on behalf of the device
 *                  or {@code null} otherwise.
 * @param ctx The device's currently executing HTTP request.
 * @param responseReady A future to complete once one of the following conditions are met:
 *              <ul>
 *              <li>the request did not include a <em>hono-ttd</em> parameter or</li>
 *              <li>a command has been received and the response ready future has not yet been
 *              completed or</li>
 *              <li>the ttd has expired</li>
 *              </ul>
 * @param uploadMessageSpan The OpenTracing Span used for tracking the processing
 *                       of the request.
 * @return A future indicating the outcome of the operation.
 *         <p>
 *         The future will be completed with the created message consumer or {@code null}, if
 *         the response can be sent back to the device without waiting for a command.
 *         <p>
 *         The future will be failed with a {@code ServiceInvocationException} if the
 *         message consumer could not be created.
 * @throws NullPointerException if any of the parameters other than TTD or gatewayId is {@code null}.
 */
protected final Future<CommandConsumer> createCommandConsumer(final Integer ttdSecs, final TenantObject tenantObject, final String deviceId, final String gatewayId, final RoutingContext ctx, final Handler<AsyncResult<Void>> responseReady, final Span uploadMessageSpan) {
    Objects.requireNonNull(tenantObject);
    Objects.requireNonNull(deviceId);
    Objects.requireNonNull(ctx);
    Objects.requireNonNull(responseReady);
    Objects.requireNonNull(uploadMessageSpan);
    if (ttdSecs == null || ttdSecs <= 0) {
        // no need to wait for a command
        responseReady.handle(Future.succeededFuture());
        return Future.succeededFuture();
    }
    final AtomicBoolean requestProcessed = new AtomicBoolean(false);
    uploadMessageSpan.setTag(MessageHelper.APP_PROPERTY_DEVICE_TTD, ttdSecs);
    final Span waitForCommandSpan = TracingHelper.buildChildSpan(tracer, uploadMessageSpan.context(), "create consumer and wait for command", getTypeName()).withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT).withTag(TracingHelper.TAG_TENANT_ID, tenantObject.getTenantId()).withTag(TracingHelper.TAG_DEVICE_ID, deviceId).start();
    final Handler<CommandContext> commandHandler = commandContext -> {
        final Span processCommandSpan = TracingHelper.buildFollowsFromSpan(tracer, waitForCommandSpan.context(), "process received command").withTag(Tags.COMPONENT.getKey(), getTypeName()).withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT).withTag(TracingHelper.TAG_TENANT_ID, tenantObject.getTenantId()).withTag(TracingHelper.TAG_DEVICE_ID, deviceId).addReference(References.FOLLOWS_FROM, commandContext.getTracingContext()).start();
        Tags.COMPONENT.set(commandContext.getTracingSpan(), getTypeName());
        commandContext.logCommandToSpan(processCommandSpan);
        final Command command = commandContext.getCommand();
        final Sample commandSample = getMetrics().startTimer();
        if (isCommandValid(command, processCommandSpan)) {
            if (requestProcessed.compareAndSet(false, true)) {
                waitForCommandSpan.finish();
                checkMessageLimit(tenantObject, command.getPayloadSize(), processCommandSpan.context()).onComplete(result -> {
                    if (result.succeeded()) {
                        addMicrometerSample(commandContext, commandSample);
                        // put command context to routing context and notify
                        ctx.put(CommandContext.KEY_COMMAND_CONTEXT, commandContext);
                    } else {
                        commandContext.reject(result.cause());
                        TracingHelper.logError(processCommandSpan, "rejected command for device", result.cause());
                        metrics.reportCommand(command.isOneWay() ? Direction.ONE_WAY : Direction.REQUEST, tenantObject.getTenantId(), tenantObject, ProcessingOutcome.from(result.cause()), command.getPayloadSize(), commandSample);
                    }
                    cancelCommandReceptionTimer(ctx);
                    setTtdStatus(ctx, TtdStatus.COMMAND);
                    responseReady.handle(Future.succeededFuture());
                    processCommandSpan.finish();
                });
            } else {
                final String errorMsg = "waiting time for command has elapsed or another command has already been processed";
                log.debug("{} [tenantId: {}, deviceId: {}]", errorMsg, tenantObject.getTenantId(), deviceId);
                getMetrics().reportCommand(command.isOneWay() ? Direction.ONE_WAY : Direction.REQUEST, tenantObject.getTenantId(), tenantObject, ProcessingOutcome.UNDELIVERABLE, command.getPayloadSize(), commandSample);
                commandContext.release(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, errorMsg));
                TracingHelper.logError(processCommandSpan, errorMsg);
                processCommandSpan.finish();
            }
        } else {
            getMetrics().reportCommand(command.isOneWay() ? Direction.ONE_WAY : Direction.REQUEST, tenantObject.getTenantId(), tenantObject, ProcessingOutcome.UNPROCESSABLE, command.getPayloadSize(), commandSample);
            log.debug("command message is invalid: {}", command);
            commandContext.reject("malformed command message");
            TracingHelper.logError(processCommandSpan, "malformed command message");
            processCommandSpan.finish();
        }
    };
    final Future<CommandConsumer> commandConsumerFuture;
    if (gatewayId != null) {
        // gateway scenario
        commandConsumerFuture = getCommandConsumerFactory().createCommandConsumer(tenantObject.getTenantId(), deviceId, gatewayId, commandHandler, Duration.ofSeconds(ttdSecs), waitForCommandSpan.context());
    } else {
        commandConsumerFuture = getCommandConsumerFactory().createCommandConsumer(tenantObject.getTenantId(), deviceId, commandHandler, Duration.ofSeconds(ttdSecs), waitForCommandSpan.context());
    }
    return commandConsumerFuture.onFailure(thr -> {
        TracingHelper.logError(waitForCommandSpan, thr);
        waitForCommandSpan.finish();
    }).map(consumer -> {
        if (!requestProcessed.get()) {
            // if the request was not responded already, add a timer for triggering an empty response
            addCommandReceptionTimer(ctx, requestProcessed, responseReady, ttdSecs, waitForCommandSpan);
        }
        // for unregistering the command consumer (which is something the parent request span doesn't wait for)
        return new CommandConsumer() {

            @Override
            public Future<Void> close(final SpanContext ignored) {
                final Span closeConsumerSpan = TracingHelper.buildFollowsFromSpan(tracer, waitForCommandSpan.context(), "close consumer").withTag(Tags.COMPONENT.getKey(), getTypeName()).withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT).withTag(TracingHelper.TAG_TENANT_ID, tenantObject.getTenantId()).withTag(TracingHelper.TAG_DEVICE_ID, deviceId).start();
                return consumer.close(closeConsumerSpan.context()).onFailure(thr -> TracingHelper.logError(closeConsumerSpan, thr)).onComplete(ar -> closeConsumerSpan.finish());
            }
        };
    });
}
Also used : HttpURLConnection(java.net.HttpURLConnection) HttpServer(io.vertx.core.http.HttpServer) Router(io.vertx.ext.web.Router) RoutingContext(io.vertx.ext.web.RoutingContext) BodyHandler(io.vertx.ext.web.handler.BodyHandler) Tags(io.opentracing.tag.Tags) ProcessingOutcome(org.eclipse.hono.service.metric.MetricsTags.ProcessingOutcome) EndpointType(org.eclipse.hono.service.metric.MetricsTags.EndpointType) TtdStatus(org.eclipse.hono.service.metric.MetricsTags.TtdStatus) DeviceCredentials(org.eclipse.hono.adapter.auth.device.DeviceCredentials) References(io.opentracing.References) Duration(java.time.Duration) Map(java.util.Map) WebSpanDecorator(org.eclipse.hono.service.http.WebSpanDecorator) TracingHelper(org.eclipse.hono.tracing.TracingHelper) CommandContext(org.eclipse.hono.client.command.CommandContext) MetricsTags(org.eclipse.hono.service.metric.MetricsTags) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) MessageHelper(org.eclipse.hono.util.MessageHelper) Future(io.vertx.core.Future) Device(org.eclipse.hono.auth.Device) Objects(java.util.Objects) List(java.util.List) ComponentMetaDataDecorator(org.eclipse.hono.service.http.ComponentMetaDataDecorator) TenantTraceSamplingHelper(org.eclipse.hono.tracing.TenantTraceSamplingHelper) Buffer(io.vertx.core.buffer.Buffer) CommandConsumer(org.eclipse.hono.client.command.CommandConsumer) HttpServerResponse(io.vertx.core.http.HttpServerResponse) DefaultFailureHandler(org.eclipse.hono.service.http.DefaultFailureHandler) Optional(java.util.Optional) Span(io.opentracing.Span) HttpContext(org.eclipse.hono.service.http.HttpContext) Command(org.eclipse.hono.client.command.Command) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) ClientErrorException(org.eclipse.hono.client.ClientErrorException) Constants(org.eclipse.hono.util.Constants) ArrayList(java.util.ArrayList) TracingHandler(org.eclipse.hono.service.http.TracingHandler) CompositeFuture(io.vertx.core.CompositeFuture) HttpUtils(org.eclipse.hono.service.http.HttpUtils) AsyncResult(io.vertx.core.AsyncResult) Strings(org.eclipse.hono.util.Strings) Route(io.vertx.ext.web.Route) 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) Sample(io.micrometer.core.instrument.Timer.Sample) CommandResponse(org.eclipse.hono.client.command.CommandResponse) TenantObject(org.eclipse.hono.util.TenantObject) SpanContext(io.opentracing.SpanContext) HttpServerOptions(io.vertx.core.http.HttpServerOptions) NoopSpan(io.opentracing.noop.NoopSpan) Handler(io.vertx.core.Handler) SpanContext(io.opentracing.SpanContext) CommandContext(org.eclipse.hono.client.command.CommandContext) Sample(io.micrometer.core.instrument.Timer.Sample) Span(io.opentracing.Span) NoopSpan(io.opentracing.noop.NoopSpan) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Command(org.eclipse.hono.client.command.Command) CommandConsumer(org.eclipse.hono.client.command.CommandConsumer) ServerErrorException(org.eclipse.hono.client.ServerErrorException)

Example 97 with Device

use of org.eclipse.hono.auth.Device in project hono by eclipse.

the class VertxBasedHttpProtocolAdapter method handlePostCommandResponse.

void handlePostCommandResponse(final RoutingContext ctx) {
    if (Device.class.isInstance(ctx.user())) {
        final Device device = (Device) ctx.user();
        uploadCommandResponseMessage(HttpContext.from(ctx), device.getTenantId(), device.getDeviceId(), getCommandRequestIdParam(ctx), getCommandResponseStatusParam(ctx));
    } else {
        handle401(ctx);
    }
}
Also used : Device(org.eclipse.hono.auth.Device)

Example 98 with Device

use of org.eclipse.hono.auth.Device in project hono by eclipse.

the class VertxBasedHttpProtocolAdapter method handlePostEvent.

void handlePostEvent(final RoutingContext ctx) {
    if (Device.class.isInstance(ctx.user())) {
        final Device device = (Device) ctx.user();
        uploadEventMessage(HttpContext.from(ctx), device.getTenantId(), device.getDeviceId());
    } else {
        handle401(ctx);
    }
}
Also used : Device(org.eclipse.hono.auth.Device)

Example 99 with Device

use of org.eclipse.hono.auth.Device in project hono by eclipse.

the class LoraProtocolAdapter method handleOptionsRoute.

void handleOptionsRoute(final RoutingContext ctx) {
    final Span currentSpan = TracingHelper.buildServerChildSpan(tracer, TracingHandler.serverSpanContext(ctx), "process OPTIONS request", getClass().getSimpleName()).start();
    if (ctx.user() instanceof Device) {
        currentSpan.finish();
        // Some providers use OPTIONS request to check if request works. Therefore returning 200.
        handle200(ctx);
    } else {
        logUnsupportedUserType(ctx, currentSpan);
        currentSpan.finish();
        handle401(ctx);
    }
}
Also used : Device(org.eclipse.hono.auth.Device) Span(io.opentracing.Span)

Example 100 with Device

use of org.eclipse.hono.auth.Device in project hono by eclipse.

the class AbstractProtocolAdapterBaseTest method testCheckConnectionDurationLimit.

/**
 * Verifies that the connection duration check fails if the tenant's connection duration
 * limit has been already reached.
 *
 * @param ctx The vert.x test context.
 */
@Test
public void testCheckConnectionDurationLimit(final VertxTestContext ctx) {
    // Given a tenant for which the maximum connection duration usage already exceeds the limit.
    final TenantObject tenant = TenantObject.from("tenant", Boolean.TRUE);
    final ResourceLimitChecks checks = mock(ResourceLimitChecks.class);
    when(checks.isConnectionDurationLimitReached(any(TenantObject.class), any(SpanContext.class))).thenReturn(Future.succeededFuture(Boolean.TRUE));
    adapter.setResourceLimitChecks(checks);
    // When a device tries to connect
    adapter.checkConnectionDurationLimit(tenant, mock(SpanContext.class)).onComplete(ctx.failing(t -> {
        // Then the connection duration limit check fails
        ctx.verify(() -> {
            assertThat(t).isInstanceOf(ConnectionDurationExceededException.class);
            assertThat(t).hasMessageThat().isEqualTo(ServiceInvocationException.getLocalizedMessage(ConnectionDurationExceededException.MESSAGE_KEY));
        });
        ctx.completeNow();
    }));
}
Also used : HttpURLConnection(java.net.HttpURLConnection) BeforeEach(org.junit.jupiter.api.BeforeEach) ArgumentMatchers.argThat(org.mockito.ArgumentMatchers.argThat) ArgumentMatchers.eq(org.mockito.ArgumentMatchers.eq) TenantConstants(org.eclipse.hono.util.TenantConstants) Context(io.vertx.core.Context) TelemetrySender(org.eclipse.hono.client.telemetry.TelemetrySender) MessagingType(org.eclipse.hono.util.MessagingType) Assertions.assertFalse(org.junit.jupiter.api.Assertions.assertFalse) ExtendWith(org.junit.jupiter.api.extension.ExtendWith) Map(java.util.Map) CredentialsClient(org.eclipse.hono.client.registry.CredentialsClient) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) EventSender(org.eclipse.hono.client.telemetry.EventSender) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) TenantClient(org.eclipse.hono.client.registry.TenantClient) MessageHelper(org.eclipse.hono.util.MessageHelper) VertxExtension(io.vertx.junit5.VertxExtension) EventConstants(org.eclipse.hono.util.EventConstants) Future(io.vertx.core.Future) Device(org.eclipse.hono.auth.Device) Test(org.junit.jupiter.api.Test) List(java.util.List) Buffer(io.vertx.core.buffer.Buffer) VertxMockSupport(org.eclipse.hono.test.VertxMockSupport) CommandRouterClient(org.eclipse.hono.client.command.CommandRouterClient) Assertions.assertTrue(org.junit.jupiter.api.Assertions.assertTrue) Optional(java.util.Optional) Mockito.mock(org.mockito.Mockito.mock) ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) VertxTestContext(io.vertx.junit5.VertxTestContext) ArgumentMatchers.anyLong(org.mockito.ArgumentMatchers.anyLong) HashMap(java.util.HashMap) ClientErrorException(org.eclipse.hono.client.ClientErrorException) ConnectionEventProducer(org.eclipse.hono.adapter.monitoring.ConnectionEventProducer) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) CommandResponseSender(org.eclipse.hono.client.command.CommandResponseSender) Commands(org.eclipse.hono.client.command.Commands) Constants(org.eclipse.hono.util.Constants) TelemetryConstants(org.eclipse.hono.util.TelemetryConstants) ArgumentCaptor(org.mockito.ArgumentCaptor) DeviceRegistrationClient(org.eclipse.hono.client.registry.DeviceRegistrationClient) TelemetryExecutionContext(org.eclipse.hono.util.TelemetryExecutionContext) HttpUtils(org.eclipse.hono.service.http.HttpUtils) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) MessagingClient(org.eclipse.hono.util.MessagingClient) ProtocolAdapterProperties(org.eclipse.hono.config.ProtocolAdapterProperties) MessagingClientProvider(org.eclipse.hono.client.util.MessagingClientProvider) Promise(io.vertx.core.Promise) Vertx(io.vertx.core.Vertx) Mockito.when(org.mockito.Mockito.when) Truth.assertThat(com.google.common.truth.Truth.assertThat) Mockito.verify(org.mockito.Mockito.verify) CommandResponse(org.eclipse.hono.client.command.CommandResponse) TenantObject(org.eclipse.hono.util.TenantObject) SpanContext(io.opentracing.SpanContext) CommandConsumerFactory(org.eclipse.hono.client.command.CommandConsumerFactory) Mockito.never(org.mockito.Mockito.never) ResourceLimitChecks(org.eclipse.hono.adapter.resourcelimits.ResourceLimitChecks) HonoEventConnectionEventProducer(org.eclipse.hono.adapter.monitoring.HonoEventConnectionEventProducer) Handler(io.vertx.core.Handler) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) TenantObject(org.eclipse.hono.util.TenantObject) SpanContext(io.opentracing.SpanContext) ResourceLimitChecks(org.eclipse.hono.adapter.resourcelimits.ResourceLimitChecks) Test(org.junit.jupiter.api.Test)

Aggregations

Device (org.eclipse.hono.auth.Device)115 HttpURLConnection (java.net.HttpURLConnection)74 Test (org.junit.jupiter.api.Test)72 Future (io.vertx.core.Future)69 ClientErrorException (org.eclipse.hono.client.ClientErrorException)67 Buffer (io.vertx.core.buffer.Buffer)66 Handler (io.vertx.core.Handler)63 TenantObject (org.eclipse.hono.util.TenantObject)63 Promise (io.vertx.core.Promise)59 Constants (org.eclipse.hono.util.Constants)58 Span (io.opentracing.Span)55 RegistrationAssertion (org.eclipse.hono.util.RegistrationAssertion)55 SpanContext (io.opentracing.SpanContext)53 VertxTestContext (io.vertx.junit5.VertxTestContext)52 VertxExtension (io.vertx.junit5.VertxExtension)51 MessageHelper (org.eclipse.hono.util.MessageHelper)51 ExtendWith (org.junit.jupiter.api.extension.ExtendWith)51 Mockito.when (org.mockito.Mockito.when)51 Truth.assertThat (com.google.common.truth.Truth.assertThat)50 ResourceIdentifier (org.eclipse.hono.util.ResourceIdentifier)47