use of org.eclipse.hono.util.RegistrationAssertion 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);
});
}
use of org.eclipse.hono.util.RegistrationAssertion in project hono by eclipse.
the class CommandResponseResource method uploadCommandResponseMessage.
/**
* Forwards a command response to a downstream application.
*
* @param context The context representing the command response to be forwarded.
* @return A future indicating the outcome of the operation.
* The future will be succeeded if the message has been forwarded successfully.
* In this case one of the context's <em>respond</em> methods will have been invoked to send a CoAP response
* back to the device.
* Otherwise the future will be failed with a {@link org.eclipse.hono.client.ServiceInvocationException}.
* @throws NullPointerException if context is {@code null}.
*/
public final Future<Void> uploadCommandResponseMessage(final CoapContext context) {
Objects.requireNonNull(context);
final Device device = context.getOriginDevice();
final Device authenticatedDevice = context.getAuthenticatedDevice();
if (!context.isConfirmable()) {
return Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "command response endpoint supports confirmable request messages only"));
}
final Buffer payload = context.getPayload();
final String contentType = context.getContentType();
final String commandRequestId = context.getCommandRequestId();
final Integer responseStatus = context.getCommandResponseStatus();
LOG.debug("processing response to command [tenantId: {}, deviceId: {}, cmd-req-id: {}, status code: {}]", device.getTenantId(), device.getDeviceId(), commandRequestId, responseStatus);
final Span currentSpan = TracingHelper.buildChildSpan(getTracer(), context.getTracingContext(), "upload Command response", getAdapter().getTypeName()).withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT).withTag(TracingHelper.TAG_TENANT_ID, device.getTenantId()).withTag(TracingHelper.TAG_DEVICE_ID, device.getDeviceId()).withTag(Constants.HEADER_COMMAND_RESPONSE_STATUS, responseStatus).withTag(Constants.HEADER_COMMAND_REQUEST_ID, commandRequestId).withTag(TracingHelper.TAG_AUTHENTICATED.getKey(), authenticatedDevice != null).start();
final Future<RegistrationAssertion> deviceRegistrationTracker = getAdapter().getRegistrationAssertion(device.getTenantId(), device.getDeviceId(), authenticatedDevice, currentSpan.context());
final Future<TenantObject> tenantTracker = getAdapter().getTenantClient().get(device.getTenantId(), currentSpan.context());
final Optional<CommandResponse> cmdResponse = Optional.ofNullable(CommandResponse.fromRequestId(commandRequestId, device.getTenantId(), device.getDeviceId(), payload, contentType, responseStatus));
final Future<CommandResponse> commandResponseTracker = cmdResponse.map(res -> Future.succeededFuture(res)).orElseGet(() -> Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, String.format("command-request-id [%s] or status code [%s] is missing/invalid", commandRequestId, responseStatus))));
return CompositeFuture.all(tenantTracker, commandResponseTracker, deviceRegistrationTracker).compose(ok -> CompositeFuture.all(getAdapter().isAdapterEnabled(tenantTracker.result()), getAdapter().checkMessageLimit(tenantTracker.result(), payload.length(), currentSpan.context())).mapEmpty()).compose(ok -> getAdapter().getCommandResponseSender(commandResponseTracker.result().getMessagingType(), tenantTracker.result()).sendCommandResponse(tenantTracker.result(), deviceRegistrationTracker.result(), commandResponseTracker.result(), currentSpan.context())).onSuccess(ok -> {
LOG.trace("forwarded command response [command-request-id: {}] to downstream application", commandRequestId);
currentSpan.log("forwarded command response to application");
getAdapter().getMetrics().reportCommand(Direction.RESPONSE, device.getTenantId(), tenantTracker.result(), ProcessingOutcome.FORWARDED, payload.length(), context.getTimer());
context.respondWithCode(ResponseCode.CHANGED);
}).onFailure(t -> {
LOG.debug("could not send command response [command-request-id: {}] to application", commandRequestId, t);
TracingHelper.logError(currentSpan, t);
getAdapter().getMetrics().reportCommand(Direction.RESPONSE, device.getTenantId(), tenantTracker.result(), ProcessingOutcome.from(t), payload.length(), context.getTimer());
}).onComplete(r -> currentSpan.finish());
}
use of org.eclipse.hono.util.RegistrationAssertion in project hono by eclipse.
the class ProtonBasedDeviceRegistrationClient method assertRegistration.
@Override
public Future<RegistrationAssertion> assertRegistration(final String tenantId, final String deviceId, final String gatewayId, final SpanContext context) {
Objects.requireNonNull(tenantId);
Objects.requireNonNull(deviceId);
final AnnotatedCacheKey<CacheKey> responseCacheKey = new AnnotatedCacheKey<>(new CacheKey(tenantId, deviceId, gatewayId));
final Span span = newChildSpan(context, "assert Device Registration");
TracingHelper.setDeviceTags(span, tenantId, deviceId);
TracingHelper.TAG_GATEWAY_ID.set(span, gatewayId);
return getResponseFromCache(responseCacheKey, span).recover(t -> getOrCreateClient(tenantId).compose(client -> {
final Map<String, Object> properties = createDeviceIdProperties(deviceId);
if (gatewayId != null) {
properties.put(MessageHelper.APP_PROPERTY_GATEWAY_ID, gatewayId);
}
return client.createAndSendRequest(RegistrationConstants.ACTION_ASSERT, properties, null, RegistrationConstants.CONTENT_TYPE_APPLICATION_JSON, this::getRequestResponseResult, span);
}).map(registrationResult -> {
addToCache(responseCacheKey, registrationResult);
return registrationResult;
})).recover(t -> {
Tags.HTTP_STATUS.set(span, ServiceInvocationException.extractStatusCode(t));
TracingHelper.logError(span, t);
return Future.failedFuture(t);
}).map(registrationResult -> {
Tags.HTTP_STATUS.set(span, registrationResult.getStatus());
if (registrationResult.isError()) {
Tags.ERROR.set(span, Boolean.TRUE);
}
switch(registrationResult.getStatus()) {
case HttpURLConnection.HTTP_OK:
final JsonObject payload = registrationResult.getPayload();
try {
return payload.mapTo(RegistrationAssertion.class);
} catch (final DecodeException e) {
if (log.isDebugEnabled()) {
log.debug("registration service returned invalid response:{}{}", System.lineSeparator(), payload.encodePrettily());
}
TracingHelper.logError(span, "registration service returned invalid response", e);
throw new ServerErrorException(HttpURLConnection.HTTP_INTERNAL_ERROR, "registration service returned invalid response");
}
case HttpURLConnection.HTTP_NOT_FOUND:
throw new ClientErrorException(registrationResult.getStatus(), "device unknown or disabled");
case HttpURLConnection.HTTP_FORBIDDEN:
throw new ClientErrorException(registrationResult.getStatus(), "gateway unknown, disabled or not authorized to act on behalf of device");
default:
throw StatusCodeMapper.from(registrationResult);
}
}).onComplete(o -> span.finish());
}
use of org.eclipse.hono.util.RegistrationAssertion in project hono by eclipse.
the class JmsBasedRegistrationClient method sendRequest.
/**
* Sends a request for an operation.
*
* @param tenantId The tenant to send the request for.
* @param operation The name of the operation to invoke or {@code null} if the message
* should not have a subject.
* @param applicationProperties Application properties to set on the request message or
* {@code null} if no properties should be set.
* @param payload Payload to include or {@code null} if the message should have no body.
* @return A future indicating the outcome of the operation.
*/
public Future<RegistrationAssertion> sendRequest(final String tenantId, final String operation, final Map<String, Object> applicationProperties, final Buffer payload) {
final Message request;
try {
request = createMessage(payload);
addProperties(request, applicationProperties);
if (operation != null) {
request.setJMSType(operation);
}
} catch (final JMSException e) {
return Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST));
}
final Future<JmsBasedRequestResponseClient<RegistrationResult>> client = JmsBasedRequestResponseClient.forEndpoint(connection, RegistrationConstants.REGISTRATION_ENDPOINT, tenantId);
return client.compose(c -> c.send(request, this::getResult)).compose(registrationResult -> {
final Promise<RegistrationAssertion> result = Promise.promise();
switch(registrationResult.getStatus()) {
case HttpURLConnection.HTTP_OK:
try {
final var assertion = registrationResult.getPayload().mapTo(RegistrationAssertion.class);
result.complete(assertion);
} catch (final DecodeException e) {
result.fail(e);
}
break;
case HttpURLConnection.HTTP_NOT_FOUND:
result.fail(new ClientErrorException(registrationResult.getStatus(), "no such device"));
break;
default:
result.fail(StatusCodeMapper.from(registrationResult));
}
return result.future();
});
}
use of org.eclipse.hono.util.RegistrationAssertion in project hono by eclipse.
the class AbstractProtocolAdapterBaseTest method testGetRegistrationAssertionSucceedsForExistingDevice.
/**
* Verifies that the adapter successfully retrieves a registration assertion
* for an existing device.
*
* @param ctx The vert.x test context.
*/
@Test
public void testGetRegistrationAssertionSucceedsForExistingDevice(final VertxTestContext ctx) {
// GIVEN an adapter connected to a registration service
final RegistrationAssertion assertionResult = newRegistrationAssertionResult("device");
assertionResult.setAuthorizedGateways(List.of("gw", "gw2"));
when(registrationClient.assertRegistration(eq("tenant"), eq("device"), any(), any())).thenReturn(Future.succeededFuture(assertionResult));
when(commandRouterClient.setLastKnownGatewayForDevice(anyString(), anyString(), anyString(), any())).thenReturn(Future.succeededFuture());
// WHEN an assertion for the device is retrieved
adapter.getRegistrationAssertion("tenant", "device", new Device("tenant", "gw"), mock(SpanContext.class)).onComplete(ctx.succeeding(result -> {
ctx.verify(() -> {
// THEN the result contains the registration assertion
assertThat(result.getDeviceId()).isEqualTo("device");
// and the last known gateway has been updated
verify(commandRouterClient).setLastKnownGatewayForDevice(eq("tenant"), eq("device"), eq("gw"), any());
});
ctx.completeNow();
}));
}
Aggregations