Search in sources :

Example 16 with Promise

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

the class AbstractVertxBasedHttpProtocolAdapter method doUploadMessage.

private void doUploadMessage(final HttpContext ctx, final String tenant, final String deviceId, final Buffer payload, final String contentType, final MetricsTags.EndpointType endpoint) {
    if (!ctx.hasValidQoS()) {
        HttpUtils.badRequest(ctx.getRoutingContext(), "unsupported QoS-Level header value");
        return;
    }
    if (!isPayloadOfIndicatedType(payload, contentType)) {
        HttpUtils.badRequest(ctx.getRoutingContext(), String.format("content type [%s] does not match payload", contentType));
        return;
    }
    final MetricsTags.QoS qos = getQoSLevel(endpoint, ctx.getRequestedQos());
    final Device authenticatedDevice = ctx.getAuthenticatedDevice();
    final String gatewayId = authenticatedDevice != null && !deviceId.equals(authenticatedDevice.getDeviceId()) ? authenticatedDevice.getDeviceId() : null;
    final Span currentSpan = TracingHelper.buildChildSpan(tracer, TracingHandler.serverSpanContext(ctx.getRoutingContext()), "upload " + endpoint.getCanonicalName(), getTypeName()).withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT).withTag(TracingHelper.TAG_TENANT_ID, tenant).withTag(TracingHelper.TAG_DEVICE_ID, deviceId).withTag(TracingHelper.TAG_AUTHENTICATED.getKey(), authenticatedDevice != null).withTag(TracingHelper.TAG_QOS, qos.name()).start();
    final Promise<Void> responseReady = Promise.promise();
    final Future<RegistrationAssertion> tokenTracker = getRegistrationAssertion(tenant, deviceId, authenticatedDevice, currentSpan.context());
    final int payloadSize = Optional.ofNullable(payload).map(ok -> payload.length()).orElse(0);
    final Future<TenantObject> tenantTracker = getTenantConfiguration(tenant, currentSpan.context());
    final Future<TenantObject> tenantValidationTracker = tenantTracker.compose(tenantObject -> CompositeFuture.all(isAdapterEnabled(tenantObject), checkMessageLimit(tenantObject, payloadSize, currentSpan.context())).map(success -> 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 = getTimeUntilDisconnectFromRequest(ctx);
        return 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, ctx.getRoutingContext(), responseReady, currentSpan));
    commandConsumerTracker.compose(ok -> {
        final Map<String, Object> props = getDownstreamMessageProperties(ctx);
        Optional.ofNullable(commandConsumerTracker.result()).map(c -> ttdTracker.result()).ifPresent(ttd -> props.put(MessageHelper.APP_PROPERTY_DEVICE_TTD, ttd));
        props.put(MessageHelper.APP_PROPERTY_QOS, ctx.getRequestedQos().ordinal());
        customizeDownstreamMessageProperties(props, ctx);
        setTtdRequestConnectionCloseHandler(ctx.getRoutingContext(), commandConsumerTracker.result(), tenant, deviceId, currentSpan);
        if (EndpointType.EVENT.equals(endpoint)) {
            ctx.getTimeToLive().ifPresent(ttl -> props.put(MessageHelper.SYS_HEADER_PROPERTY_TTL, ttl.toSeconds()));
            return CompositeFuture.all(getEventSender(tenantValidationTracker.result()).sendEvent(tenantTracker.result(), tokenTracker.result(), contentType, payload, props, currentSpan.context()), responseReady.future()).map(s -> (Void) null);
        } else {
            // unsettled
            return CompositeFuture.all(getTelemetrySender(tenantValidationTracker.result()).sendTelemetry(tenantTracker.result(), tokenTracker.result(), ctx.getRequestedQos(), contentType, payload, props, currentSpan.context()), responseReady.future()).map(s -> (Void) null);
        }
    }).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 -> {
        if (ctx.response().closed()) {
            log.debug("failed to send http response for [{}] message from device [tenantId: {}, deviceId: {}]: response already closed", endpoint, tenant, deviceId);
            TracingHelper.logError(currentSpan, "failed to send HTTP response to device: response already closed");
            currentSpan.finish();
            // close the response here, ensuring that the TracingHandler bodyEndHandler gets called
            ctx.response().end();
        } else {
            final CommandContext commandContext = ctx.get(CommandContext.KEY_COMMAND_CONTEXT);
            setResponsePayload(ctx.response(), commandContext, currentSpan);
            ctx.getRoutingContext().addBodyEndHandler(ok -> {
                log.trace("successfully processed [{}] message for device [tenantId: {}, deviceId: {}]", endpoint, tenant, deviceId);
                if (commandContext != null) {
                    commandContext.getTracingSpan().log("forwarded command to device in HTTP response body");
                    commandContext.accept();
                    metrics.reportCommand(commandContext.getCommand().isOneWay() ? Direction.ONE_WAY : Direction.REQUEST, tenant, tenantTracker.result(), ProcessingOutcome.FORWARDED, commandContext.getCommand().getPayloadSize(), getMicrometerSample(commandContext));
                }
                metrics.reportTelemetry(endpoint, tenant, tenantTracker.result(), ProcessingOutcome.FORWARDED, qos, payloadSize, ctx.getTtdStatus(), getMicrometerSample(ctx.getRoutingContext()));
                currentSpan.finish();
            });
            ctx.response().exceptionHandler(t -> {
                log.debug("failed to send http response for [{}] message from device [tenantId: {}, deviceId: {}]", endpoint, tenant, deviceId, t);
                if (commandContext != null) {
                    TracingHelper.logError(commandContext.getTracingSpan(), "failed to forward command to device in HTTP response body", t);
                    commandContext.release(t);
                    metrics.reportCommand(commandContext.getCommand().isOneWay() ? Direction.ONE_WAY : Direction.REQUEST, tenant, tenantTracker.result(), ProcessingOutcome.UNDELIVERABLE, commandContext.getCommand().getPayloadSize(), getMicrometerSample(commandContext));
                }
                currentSpan.log("failed to send HTTP response to device");
                TracingHelper.logError(currentSpan, t);
                currentSpan.finish();
            });
            ctx.response().end();
        }
        return proceed;
    }).recover(t -> {
        log.debug("cannot process [{}] message from device [tenantId: {}, deviceId: {}]", endpoint, tenant, deviceId, t);
        final boolean responseClosedPrematurely = ctx.response().closed();
        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 = ctx.get(CommandContext.KEY_COMMAND_CONTEXT);
        if (commandContext != null) {
            TracingHelper.logError(commandContext.getTracingSpan(), "command won't be forwarded to device in HTTP response body, HTTP request handling failed", t);
            commandContext.release(t);
            currentSpan.log("released command for device");
        }
        final ProcessingOutcome outcome;
        if (ClientErrorException.class.isInstance(t)) {
            outcome = ProcessingOutcome.UNPROCESSABLE;
            ctx.fail(t);
        } else {
            outcome = ProcessingOutcome.UNDELIVERABLE;
            final String errorMessage = t instanceof ServerErrorException ? ((ServerErrorException) t).getClientFacingMessage() : null;
            HttpUtils.serviceUnavailable(ctx.getRoutingContext(), 2, Strings.isNullOrEmpty(errorMessage) ? "temporarily unavailable" : errorMessage);
        }
        if (responseClosedPrematurely) {
            log.debug("failed to send http response for [{}] message from device [tenantId: {}, deviceId: {}]: response already closed", endpoint, tenant, deviceId);
            TracingHelper.logError(currentSpan, "failed to send HTTP response to device: response already closed");
        }
        metrics.reportTelemetry(endpoint, tenant, tenantTracker.result(), outcome, qos, payloadSize, ctx.getTtdStatus(), getMicrometerSample(ctx.getRoutingContext()));
        TracingHelper.logError(currentSpan, t);
        commandConsumerClosedTracker.onComplete(res -> currentSpan.finish());
        return Future.failedFuture(t);
    });
}
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) CommandContext(org.eclipse.hono.client.command.CommandContext) Device(org.eclipse.hono.auth.Device) Span(io.opentracing.Span) NoopSpan(io.opentracing.noop.NoopSpan) ProcessingOutcome(org.eclipse.hono.service.metric.MetricsTags.ProcessingOutcome) TenantObject(org.eclipse.hono.util.TenantObject) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) CommandConsumer(org.eclipse.hono.client.command.CommandConsumer) MetricsTags(org.eclipse.hono.service.metric.MetricsTags) Future(io.vertx.core.Future) CompositeFuture(io.vertx.core.CompositeFuture) ServerErrorException(org.eclipse.hono.client.ServerErrorException) Map(java.util.Map) HashMap(java.util.HashMap)

Example 17 with Promise

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

the class TelemetryResourceTest method testUploadTelemetryReleasesCommandForFailedDownstreamSender.

/**
 * Verifies that the adapter releases an incoming command if the forwarding of the preceding telemetry
 * message did not succeed.
 *
 * @param ctx The vert.x test context.
 */
@Test
public void testUploadTelemetryReleasesCommandForFailedDownstreamSender(final VertxTestContext ctx) {
    // GIVEN an adapter with a downstream telemetry consumer attached
    givenAnAdapter(properties);
    final Promise<Void> sendTelemetryOutcome = Promise.promise();
    givenATelemetrySenderForAnyTenant(sendTelemetryOutcome);
    final var resource = givenAResource(adapter);
    // and a commandConsumerFactory that upon creating a consumer will invoke it with a command
    final CommandContext commandContext = givenAOneWayCommandContext("tenant", "device", "doThis", null, null);
    when(commandConsumerFactory.createCommandConsumer(eq("tenant"), eq("device"), VertxMockSupport.anyHandler(), any(), any())).thenAnswer(invocation -> {
        final Handler<CommandContext> consumer = invocation.getArgument(2);
        consumer.handle(commandContext);
        return Future.succeededFuture(commandConsumer);
    });
    // WHEN a device publishes a telemetry message with a hono-ttd parameter
    final Buffer payload = Buffer.buffer("some payload");
    final OptionSet options = new OptionSet();
    options.addUriQuery(String.format("%s=%d", Constants.HEADER_TIME_TILL_DISCONNECT, 20));
    options.setContentFormat(MediaTypeRegistry.TEXT_PLAIN);
    final CoapExchange coapExchange = newCoapExchange(payload, Type.CON, options);
    final Device authenticatedDevice = new Device("tenant", "device");
    final CoapContext context = CoapContext.fromRequest(coapExchange, authenticatedDevice, authenticatedDevice, "device", span);
    final Future<Void> result = resource.handlePostRequest(context);
    // THEN the message is being forwarded downstream
    assertTelemetryMessageHasBeenSentDownstream(QoS.AT_LEAST_ONCE, "tenant", "device", "text/plain");
    // with no response being sent to the device yet
    verify(coapExchange, never()).respond(any(Response.class));
    // WHEN the telemetry message delivery gets failed with an exception representing a "released" delivery outcome
    sendTelemetryOutcome.fail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE));
    result.onComplete(ctx.failing(t -> {
        ctx.verify(() -> {
            // THEN the device gets a response with code SERVICE_UNAVAILABLE
            assertThat(t).isInstanceOf(ServerErrorException.class);
            assertThat(((ServerErrorException) t).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_UNAVAILABLE);
            verify(metrics).reportTelemetry(eq(MetricsTags.EndpointType.TELEMETRY), eq("tenant"), any(), eq(ProcessingOutcome.UNDELIVERABLE), eq(MetricsTags.QoS.AT_LEAST_ONCE), eq(payload.length()), eq(TtdStatus.COMMAND), any());
            // and the command delivery is released
            verify(commandContext).release(any(Throwable.class));
        });
        ctx.completeNow();
    }));
}
Also used : Buffer(io.vertx.core.buffer.Buffer) ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) HttpURLConnection(java.net.HttpURLConnection) ResponseCode(org.eclipse.californium.core.coap.CoAP.ResponseCode) VertxTestContext(io.vertx.junit5.VertxTestContext) CoapExchange(org.eclipse.californium.core.server.resources.CoapExchange) Response(org.eclipse.californium.core.coap.Response) ArgumentMatchers.anyLong(org.mockito.ArgumentMatchers.anyLong) ArgumentMatchers.argThat(org.mockito.ArgumentMatchers.argThat) ArgumentMatchers.eq(org.mockito.ArgumentMatchers.eq) ClientErrorException(org.eclipse.hono.client.ClientErrorException) Constants(org.eclipse.hono.util.Constants) Timeout(io.vertx.junit5.Timeout) ProcessingOutcome(org.eclipse.hono.service.metric.MetricsTags.ProcessingOutcome) TtdStatus(org.eclipse.hono.service.metric.MetricsTags.TtdStatus) ExtendWith(org.junit.jupiter.api.extension.ExtendWith) MediaTypeRegistry(org.eclipse.californium.core.coap.MediaTypeRegistry) CommandConstants(org.eclipse.hono.util.CommandConstants) ArgumentMatchers.anyInt(org.mockito.ArgumentMatchers.anyInt) Type(org.eclipse.californium.core.coap.CoAP.Type) Direction(org.eclipse.hono.service.metric.MetricsTags.Direction) NoopTracerFactory(io.opentracing.noop.NoopTracerFactory) Promise(io.vertx.core.Promise) CommandContext(org.eclipse.hono.client.command.CommandContext) MetricsTags(org.eclipse.hono.service.metric.MetricsTags) ServerErrorException(org.eclipse.hono.client.ServerErrorException) Mockito.when(org.mockito.Mockito.when) Truth.assertThat(com.google.common.truth.Truth.assertThat) Sample(io.micrometer.core.instrument.Timer.Sample) VertxExtension(io.vertx.junit5.VertxExtension) EventConstants(org.eclipse.hono.util.EventConstants) Future(io.vertx.core.Future) Device(org.eclipse.hono.auth.Device) Mockito.verify(org.mockito.Mockito.verify) TenantObject(org.eclipse.hono.util.TenantObject) TimeUnit(java.util.concurrent.TimeUnit) Test(org.junit.jupiter.api.Test) Mockito.never(org.mockito.Mockito.never) Buffer(io.vertx.core.buffer.Buffer) VertxMockSupport(org.eclipse.hono.test.VertxMockSupport) OptionSet(org.eclipse.californium.core.coap.OptionSet) Handler(io.vertx.core.Handler) QoS(org.eclipse.hono.util.QoS) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) Mockito.mock(org.mockito.Mockito.mock) CommandContext(org.eclipse.hono.client.command.CommandContext) Device(org.eclipse.hono.auth.Device) Response(org.eclipse.californium.core.coap.Response) ServerErrorException(org.eclipse.hono.client.ServerErrorException) OptionSet(org.eclipse.californium.core.coap.OptionSet) CoapExchange(org.eclipse.californium.core.server.resources.CoapExchange) Test(org.junit.jupiter.api.Test)

Example 18 with Promise

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

the class CommandResponseResourceTest method testUploadCommandResponseFailsForRejectedOutcome.

/**
 * Verifies that the adapter fails the upload of a command response with a 4.00
 * response code if it is rejected by the downstream peer.
 *
 * @param ctx The vert.x test context.
 */
@Test
public void testUploadCommandResponseFailsForRejectedOutcome(final VertxTestContext ctx) {
    // GIVEN an adapter with a downstream application attached
    givenAnAdapter(properties);
    final var resource = givenAResource(adapter);
    final Promise<Void> outcome = Promise.promise();
    final CommandResponseSender sender = givenACommandResponseSenderForAnyTenant(outcome);
    // WHEN a device publishes an command response
    final String reqId = Commands.encodeRequestIdParameters("correlation", "replyToId", "device", MessagingType.amqp);
    final Buffer payload = Buffer.buffer("some payload");
    final OptionSet options = new OptionSet();
    options.addUriPath(CommandConstants.COMMAND_RESPONSE_ENDPOINT).addUriPath(reqId);
    options.addUriQuery(String.format("%s=%d", Constants.HEADER_COMMAND_RESPONSE_STATUS, 200));
    options.setContentFormat(MediaTypeRegistry.TEXT_PLAIN);
    final CoapExchange coapExchange = newCoapExchange(payload, Type.CON, options);
    final Device authenticatedDevice = new Device("tenant", "device");
    final CoapContext context = CoapContext.fromRequest(coapExchange, authenticatedDevice, authenticatedDevice, "device", span);
    final Future<Void> result = resource.uploadCommandResponseMessage(context);
    outcome.fail(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "malformed message"));
    result.onComplete(ctx.failing(t -> {
        ctx.verify(() -> {
            // THEN the command response is being forwarded downstream
            verify(sender).sendCommandResponse(any(TenantObject.class), any(RegistrationAssertion.class), any(CommandResponse.class), any(SpanContext.class));
            // and the device gets a 4.00 response
            assertThat(t).isInstanceOf(ClientErrorException.class);
            assertThat(((ClientErrorException) t).getErrorCode()).isEqualTo(HttpURLConnection.HTTP_BAD_REQUEST);
            // and the response has not been reported as forwarded
            verify(metrics, never()).reportCommand(eq(Direction.RESPONSE), eq("tenant"), any(), eq(ProcessingOutcome.FORWARDED), anyInt(), any());
        });
        ctx.completeNow();
    }));
}
Also used : Buffer(io.vertx.core.buffer.Buffer) ArgumentMatchers.any(org.mockito.ArgumentMatchers.any) HttpURLConnection(java.net.HttpURLConnection) ResponseCode(org.eclipse.californium.core.coap.CoAP.ResponseCode) VertxTestContext(io.vertx.junit5.VertxTestContext) CoapExchange(org.eclipse.californium.core.server.resources.CoapExchange) Response(org.eclipse.californium.core.coap.Response) ArgumentMatchers.argThat(org.mockito.ArgumentMatchers.argThat) ArgumentMatchers.eq(org.mockito.ArgumentMatchers.eq) ClientErrorException(org.eclipse.hono.client.ClientErrorException) CommandResponseSender(org.eclipse.hono.client.command.CommandResponseSender) Commands(org.eclipse.hono.client.command.Commands) Constants(org.eclipse.hono.util.Constants) Timeout(io.vertx.junit5.Timeout) ProcessingOutcome(org.eclipse.hono.service.metric.MetricsTags.ProcessingOutcome) MessagingType(org.eclipse.hono.util.MessagingType) ExtendWith(org.junit.jupiter.api.extension.ExtendWith) MediaTypeRegistry(org.eclipse.californium.core.coap.MediaTypeRegistry) CommandConstants(org.eclipse.hono.util.CommandConstants) ArgumentMatchers.anyInt(org.mockito.ArgumentMatchers.anyInt) Type(org.eclipse.californium.core.coap.CoAP.Type) Direction(org.eclipse.hono.service.metric.MetricsTags.Direction) NoopTracerFactory(io.opentracing.noop.NoopTracerFactory) Promise(io.vertx.core.Promise) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) Mockito.when(org.mockito.Mockito.when) Truth.assertThat(com.google.common.truth.Truth.assertThat) VertxExtension(io.vertx.junit5.VertxExtension) Future(io.vertx.core.Future) Device(org.eclipse.hono.auth.Device) Mockito.verify(org.mockito.Mockito.verify) CommandResponse(org.eclipse.hono.client.command.CommandResponse) TenantObject(org.eclipse.hono.util.TenantObject) SpanContext(io.opentracing.SpanContext) TimeUnit(java.util.concurrent.TimeUnit) Test(org.junit.jupiter.api.Test) Mockito.never(org.mockito.Mockito.never) Buffer(io.vertx.core.buffer.Buffer) OptionSet(org.eclipse.californium.core.coap.OptionSet) Device(org.eclipse.hono.auth.Device) CommandResponseSender(org.eclipse.hono.client.command.CommandResponseSender) ClientErrorException(org.eclipse.hono.client.ClientErrorException) OptionSet(org.eclipse.californium.core.coap.OptionSet) CoapExchange(org.eclipse.californium.core.server.resources.CoapExchange) Test(org.junit.jupiter.api.Test)

Example 19 with Promise

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

the class AuthenticationServerClient method getToken.

private Future<HonoUser> getToken(final ProtonConnection openCon) {
    final Promise<HonoUser> result = Promise.promise();
    final ProtonMessageHandler messageHandler = (delivery, message) -> {
        final String type = MessageHelper.getApplicationProperty(message.getApplicationProperties(), AuthenticationConstants.APPLICATION_PROPERTY_TYPE, String.class);
        if (AuthenticationConstants.TYPE_AMQP_JWT.equals(type)) {
            final String payload = MessageHelper.getPayloadAsString(message);
            if (payload != null) {
                final HonoUser user = new HonoUserAdapter() {

                    @Override
                    public String getToken() {
                        return payload;
                    }
                };
                LOG.debug("successfully retrieved token from Authentication service");
                result.complete(user);
            } else {
                result.fail(new ServerErrorException(HttpURLConnection.HTTP_INTERNAL_ERROR, "message from Authentication service contains no body"));
            }
        } else {
            result.fail(new ServerErrorException(HttpURLConnection.HTTP_INTERNAL_ERROR, "Authentication service issued unsupported token [type: " + type + "]"));
        }
    };
    openReceiver(openCon, messageHandler).onComplete(attempt -> {
        if (attempt.succeeded()) {
            vertx.setTimer(5000, tid -> {
                result.tryFail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "time out reached while waiting for token from Authentication service"));
            });
            LOG.debug("opened receiver link to Authentication service, waiting for token ...");
        } else {
            result.fail(attempt.cause());
        }
    });
    return result.future();
}
Also used : HttpURLConnection(java.net.HttpURLConnection) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonReceiver(io.vertx.proton.ProtonReceiver) HonoUserAdapter(org.eclipse.hono.auth.HonoUserAdapter) Logger(org.slf4j.Logger) Promise(io.vertx.core.Promise) MechanismMismatchException(io.vertx.proton.sasl.MechanismMismatchException) LoggerFactory(org.slf4j.LoggerFactory) Vertx(io.vertx.core.Vertx) HonoUser(org.eclipse.hono.auth.HonoUser) MessageHelper(org.eclipse.hono.util.MessageHelper) Future(io.vertx.core.Future) AuthenticationConstants(org.eclipse.hono.util.AuthenticationConstants) Objects(java.util.Objects) ConnectionFactory(org.eclipse.hono.connection.ConnectionFactory) ProtonClientOptions(io.vertx.proton.ProtonClientOptions) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) Optional(java.util.Optional) AuthenticationException(javax.security.sasl.AuthenticationException) AsyncResult(io.vertx.core.AsyncResult) Handler(io.vertx.core.Handler) HonoUser(org.eclipse.hono.auth.HonoUser) ProtonMessageHandler(io.vertx.proton.ProtonMessageHandler) HonoUserAdapter(org.eclipse.hono.auth.HonoUserAdapter)

Example 20 with Promise

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

the class AmqpConnectionIT method testConnectFailsAfterDeviceDeleted.

/**
 * Verifies that after a device has already connected successfully to the adapter, the deletion of device
 * registration data causes the adapter to refuse any following connection attempts.
 * <p>
 * This test relies upon the registration client cache data in the adapter getting deleted when the device is
 * deleted (triggered via a corresponding notification from the device registry).
 *
 * @param ctx The test context.
 */
@Test
public void testConnectFailsAfterDeviceDeleted(final VertxTestContext ctx) {
    final String tenantId = helper.getRandomTenantId();
    final String deviceId = helper.getRandomDeviceId(tenantId);
    final String password = "secret";
    final Tenant tenant = new Tenant();
    helper.registry.addDeviceForTenant(tenantId, tenant, deviceId, password).compose(ok -> connectToAdapter(IntegrationTestSupport.getUsername(deviceId, tenantId), password)).compose(con -> {
        // first connection attempt successful
        con.close();
        // now remove device
        return helper.registry.deregisterDevice(tenantId, deviceId);
    }).compose(ok -> {
        final Promise<Void> resultPromise = Promise.promise();
        // device deleted, now wait a bit for the device registry notifications to trigger registration cache invalidation
        vertx.setTimer(500, tid -> resultPromise.complete());
        return resultPromise.future();
    }).compose(ok -> connectToAdapter(IntegrationTestSupport.getUsername(deviceId, tenantId), password)).onComplete(ctx.failing(t -> {
        ctx.verify(() -> assertThat(t).isInstanceOf(AuthenticationException.class));
        ctx.completeNow();
    }));
}
Also used : HttpURLConnection(java.net.HttpURLConnection) VertxTestContext(io.vertx.junit5.VertxTestContext) KeyPair(java.security.KeyPair) CsvSource(org.junit.jupiter.params.provider.CsvSource) SelfSignedCertificate(io.vertx.core.net.SelfSignedCertificate) ClientErrorException(org.eclipse.hono.client.ClientErrorException) SaslException(javax.security.sasl.SaslException) Supplier(java.util.function.Supplier) Constants(org.eclipse.hono.util.Constants) Tenant(org.eclipse.hono.service.management.tenant.Tenant) Timeout(io.vertx.junit5.Timeout) GeneralSecurityException(java.security.GeneralSecurityException) IntegrationTestSupport(org.eclipse.hono.tests.IntegrationTestSupport) ExtendWith(org.junit.jupiter.api.extension.ExtendWith) Assumptions.assumeTrue(org.junit.jupiter.api.Assumptions.assumeTrue) JsonObject(io.vertx.core.json.JsonObject) Tenants(org.eclipse.hono.tests.Tenants) RegistryManagementConstants(org.eclipse.hono.util.RegistryManagementConstants) ValueSource(org.junit.jupiter.params.provider.ValueSource) SSLHandshakeException(javax.net.ssl.SSLHandshakeException) Promise(io.vertx.core.Promise) RegistrationConstants(org.eclipse.hono.util.RegistrationConstants) UUID(java.util.UUID) Truth.assertThat(com.google.common.truth.Truth.assertThat) VertxExtension(io.vertx.junit5.VertxExtension) Future(io.vertx.core.Future) TimeUnit(java.util.concurrent.TimeUnit) Test(org.junit.jupiter.api.Test) Adapter(org.eclipse.hono.util.Adapter) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) AuthenticationException(javax.security.sasl.AuthenticationException) Tenant(org.eclipse.hono.service.management.tenant.Tenant) Test(org.junit.jupiter.api.Test) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest)

Aggregations

Promise (io.vertx.core.Promise)155 Future (io.vertx.core.Future)122 Handler (io.vertx.core.Handler)95 List (java.util.List)86 Vertx (io.vertx.core.Vertx)85 Buffer (io.vertx.core.buffer.Buffer)83 TimeUnit (java.util.concurrent.TimeUnit)79 HttpURLConnection (java.net.HttpURLConnection)66 Logger (org.slf4j.Logger)63 LoggerFactory (org.slf4j.LoggerFactory)63 Optional (java.util.Optional)62 AsyncResult (io.vertx.core.AsyncResult)61 Truth.assertThat (com.google.common.truth.Truth.assertThat)60 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)60 VertxTestContext (io.vertx.junit5.VertxTestContext)59 Test (org.junit.jupiter.api.Test)58 Map (java.util.Map)54 UUID (java.util.UUID)52 ArrayList (java.util.ArrayList)51 JsonObject (io.vertx.core.json.JsonObject)50