private void updateRegistration(final String deviceId, final JsonObject payload, final RoutingContext ctx) { if (payload != null) { payload.remove(RegistrationConstants.FIELD_PAYLOAD_DEVICE_ID); } final String tenantId = getTenantParam(ctx); logger.debug("updating registration data for device [tenant: {}, device: {}, payload: {}]", tenantId, deviceId, payload); final JsonObject requestMsg = EventBusMessage.forOperation(RegistrationConstants.ACTION_UPDATE) .setTenant(tenantId) .setDeviceId(deviceId) .setJsonPayload(payload) .toJson(); sendAction(ctx, requestMsg, getDefaultResponseHandler(ctx)); }
private Future<EventBusMessage> processUpdateRequest(final EventBusMessage request) { final String tenantId = request.getTenant(); final String deviceId = request.getDeviceId(); final JsonObject payload = getRequestPayload(request.getJsonPayload()); if (tenantId == null || deviceId == null) { return Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST)); } else { log.debug("updating registration information for device [{}] of tenant [{}]", deviceId, tenantId); final Future<RegistrationResult> result = Future.future(); updateDevice(tenantId, deviceId, payload, result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setDeviceId(deviceId) .setCacheDirective(res.getCacheDirective()); }); } }
/** * Checks if the status code indicating the outcome of the invocation * of the operation represents an error. * * @return {@code true} if this is a response message and the status code represents an error. */ public boolean hasErrorStatus() { final Integer status = getStatus(); if (status == null) { return false; } return status >= HttpURLConnection.HTTP_BAD_REQUEST && status < 600; }
/** * Checks if this (response) message has all properties required * for successful delivery to the client. * * @return {@code true} if this message has {@code non-null} values for * properties <em>operation</em>, <em>replyToAddress</em> and * <em>correlationId</em>. */ public boolean hasResponseProperties() { return getOperation() != null && getReplyToAddress() != null && getProperty(MessageHelper.SYS_PROPERTY_CORRELATION_ID) != null; }
@Override public final void processRequest(final Message msg, final ResourceIdentifier targetAddress, final HonoUser clientPrincipal) { final EventBusMessage request = EventBusMessage.forOperation(msg) .setReplyToAddress(msg) .setAppCorrelationId(msg) .setCorrelationId(msg) .setTenant(msg) .setJsonPayload(msg); vertx.eventBus().send(TenantConstants.EVENT_BUS_ADDRESS_TENANT_IN, request.toJson()); }
@Override public final void processRequest(final Message msg, final ResourceIdentifier targetAddress, final HonoUser clientPrincipal) { final EventBusMessage registrationMsg = EventBusMessage.forOperation(msg) .setReplyToAddress(msg) .setAppCorrelationId(msg) .setCorrelationId(msg) .setTenant(targetAddress.getTenantId()) .setDeviceId(msg) .setGatewayId(msg) .setJsonPayload(msg); vertx.eventBus().send(RegistrationConstants.EVENT_BUS_ADDRESS_REGISTRATION_IN, registrationMsg.toJson()); }
Objects.requireNonNull(response); final Object correlationId = response.getCorrelationId(); final String tenantId = response.getTenant(); final String deviceId = response.getDeviceId(); final Integer status = response.getStatus(); final boolean isApplCorrelationId = response.isAppCorrelationId(); final String cacheDirective = response.getCacheDirective(); final JsonObject payload = response.getJsonPayload(); final ResourceIdentifier address = ResourceIdentifier.from(endpoint, tenantId, deviceId);
final EventBusMessage reply = forStatusCode(status); reply.setProperty( MessageHelper.SYS_PROPERTY_SUBJECT, getProperty(MessageHelper.SYS_PROPERTY_SUBJECT)); reply.setProperty( MessageHelper.ANNOTATION_X_OPT_APP_CORRELATION_ID, getProperty(MessageHelper.ANNOTATION_X_OPT_APP_CORRELATION_ID)); reply.setProperty( MessageHelper.SYS_PROPERTY_CORRELATION_ID, getProperty(MessageHelper.SYS_PROPERTY_CORRELATION_ID)); reply.setReplyToAddress(getReplyToAddress()); reply.setTenant(getTenant()); return reply;
private static EventBusMessage createRequest(final TenantConstants.TenantAction action, final JsonObject payload) { return EventBusMessage.forOperation(action.toString()) .setTenant(TEST_TENANT) .setJsonPayload(payload); }
/** * Verifies that the base service routes a deprecated request for retrieving * a tenant by its identifier to the corresponding <em>get</em> method. * * @param ctx The vert.x test context. */ @Test public void testDeprecatedGetByIdSucceeds(final TestContext ctx) { final EventBusMessage request = EventBusMessage.forOperation(TenantConstants.TenantAction.get.toString()) .setJsonPayload(new JsonObject().put(TenantConstants.FIELD_PAYLOAD_TENANT_ID, "my-tenant")); tenantService.processRequest(request).setHandler(ctx.asyncAssertSuccess(response -> { ctx.assertEquals(HttpURLConnection.HTTP_OK, response.getStatus()); ctx.assertEquals("getById", response.getJsonPayload().getString("operation")); })); }
private void processRequestMessage(final Message<JsonObject> msg) { if (log.isTraceEnabled()) { log.trace("received request message: {}", msg.body().encodePrettily()); } final EventBusMessage request = EventBusMessage.fromJson(msg.body()); processRequest(request).recover(t -> { log.debug("cannot process request [operation: {}]: {}", request.getOperation(), t.getMessage()); final int status = ServiceInvocationException.extractStatusCode(t); return Future.succeededFuture(request.getResponse(status)); }).map(response -> { if (response.getReplyToAddress() == null) { log.debug("sending response as direct reply to request [operation: {}]", request.getOperation()); msg.reply(response.toJson()); } else if (response.hasResponseProperties()) { log.debug("sending response [operation: {}, reply-to: {}]", request.getOperation(), request.getReplyToAddress()); vertx.eventBus().send(request.getReplyToAddress(), response.toJson()); } else { log.warn("discarding response lacking correlation ID or operation"); } return null; }); }
private Future<EventBusMessage> processGetByIdRequest(final EventBusMessage request, final String tenantId, final Span span) { final Future<TenantResult<JsonObject>> getResult = Future.future(); get(tenantId, span, getResult.completer()); return getResult.map(tr -> { return request.getResponse(tr.getStatus()) .setJsonPayload(tr.getPayload()) .setTenant(tenantId) .setCacheDirective(tr.getCacheDirective()); }); }
Objects.requireNonNull(response); if (response.getTenant() == null || response.getJsonPayload() == null) { return Future.succeededFuture(response); } else { final ResourceIdentifier resourceId = ResourceIdentifier.from(TenantConstants.TENANT_ENDPOINT, response.getTenant(), null); return getAuthorizationService().isAuthorized(clientPrincipal, resourceId, response.getOperation()) .map(isAuthorized -> { if (isAuthorized) {
private Future<EventBusMessage> processUpdateRequest(final EventBusMessage request) { final String tenantId = request.getTenant(); final CredentialsObject payload = Optional.ofNullable(request.getJsonPayload()) .map(json -> json.mapTo(CredentialsObject.class)).orElse(null); if (tenantId == null) { return Future.failedFuture(new ClientErrorException( HttpURLConnection.HTTP_BAD_REQUEST, "missing tenant ID")); } else if (payload == null) { return Future.failedFuture(new ClientErrorException( HttpURLConnection.HTTP_BAD_REQUEST, "missing payload")); } else { return hashPlainPasswords(payload).compose(credentials -> doUpdate(request, tenantId, credentials)); } }
Future<EventBusMessage> processGetRequest(final EventBusMessage request) { final String tenantId = request.getTenant(); final JsonObject payload = request.getJsonPayload(); final Span span = newChildSpan(SPAN_NAME_GET_TENANT, request.getSpanContext(), tenantId); final Future<EventBusMessage> resultFuture; if (tenantId == null && payload == null) {
private Future<EventBusMessage> processGetByDeviceIdRequest(final EventBusMessage request, final String tenantId, final String type, final String deviceId, final Span span) { log.debug("getting credentials for device [tenant: {}, device-id: {}]", tenantId, deviceId); span.setTag(TAG_CREDENTIALS_TYPE, type); span.setTag(MessageHelper.APP_PROPERTY_DEVICE_ID, deviceId); final Future<CredentialsResult<JsonObject>> result = Future.future(); getAll(tenantId, deviceId, span, result.completer()); return result.map(res -> { return request.getResponse(res.getStatus()) .setDeviceId(deviceId) .setJsonPayload(res.getPayload()) .setCacheDirective(res.getCacheDirective()); }); }
/** * Processes a request for a non-standard operation. * <p> * Subclasses should override this method in order to support additional, custom * operations that are not defined by Hono's Device Registration API. * <p> * This default implementation simply returns a future that is failed with a * {@link ClientErrorException} with an error code <em>400 Bad Request</em>. * * @param request The request to process. * @return A future indicating the outcome of the service invocation. */ protected Future<EventBusMessage> processCustomRegistrationMessage(final EventBusMessage request) { log.debug("invalid operation in request message [{}]", request.getOperation()); return Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST)); }
/** * Verifies that the base service routes a request for retrieving * a tenant by its identifier to the corresponding <em>get</em> method. * * @param ctx The vert.x test context. */ @Test public void testGetByIdSucceeds(final TestContext ctx) { final EventBusMessage request = createRequest(TenantConstants.TenantAction.get, null); tenantService.processRequest(request).setHandler(ctx.asyncAssertSuccess(response -> { ctx.assertEquals(HttpURLConnection.HTTP_OK, response.getStatus()); ctx.assertEquals(TEST_TENANT, response.getJsonPayload().getString(TenantConstants.FIELD_PAYLOAD_TENANT_ID)); })); }
/** * Verifies that the base service accepts a request for adding * a tenant that contains the minimum required properties. * * @param ctx The vert.x test context. */ @Test public void testAddSucceedsForMinimalData(final TestContext ctx) { final JsonObject testPayload = createValidTenantPayload(); final EventBusMessage request = createRequest(TenantConstants.TenantAction.add, testPayload); tenantService.processRequest(request).setHandler(ctx.asyncAssertSuccess(response -> { ctx.assertEquals(HttpURLConnection.HTTP_CREATED, response.getStatus()); ctx.assertEquals(TEST_TENANT, response.getTenant()); })); }
/** * Composes the given future so that the given <em>OpenTracing</em> span is finished when the future completes. * <p> * The result or exception of the given future will be used to set a {@link Tags#HTTP_STATUS} tag on the span * and to set a {@link Tags#ERROR} tag in case of an exception or a result with error status. * * @param span The span to finish. * @param resultFuture The future to be composed. * @return The composed future. */ protected Future<EventBusMessage> finishSpanOnFutureCompletion(final Span span, final Future<EventBusMessage> resultFuture) { return resultFuture.compose(eventBusMessage -> { Tags.HTTP_STATUS.set(span, eventBusMessage.getStatus()); if (eventBusMessage.hasErrorStatus()) { Tags.ERROR.set(span, true); } span.finish(); return Future.succeededFuture(eventBusMessage); }).recover(t -> { Tags.HTTP_STATUS.set(span, ServiceInvocationException.extractStatusCode(t)); TracingHelper.logError(span, t); span.finish(); return Future.failedFuture(t); }); } }