use of org.eclipse.hono.client.command.CommandContext in project hono by eclipse.
the class ProtonBasedInternalCommandConsumer method handleCommandMessage.
void handleCommandMessage(final ProtonDelivery delivery, final Message msg) {
final ProtonBasedCommand command;
try {
command = ProtonBasedCommand.fromRoutedCommandMessage(msg);
} catch (final IllegalArgumentException e) {
log.debug("address of command message is invalid: {}", msg.getAddress());
final Rejected rejected = new Rejected();
rejected.setError(new ErrorCondition(Constants.AMQP_BAD_REQUEST, "invalid command target address"));
delivery.disposition(rejected, true);
return;
}
final CommandHandlerWrapper commandHandler = commandHandlers.getCommandHandler(command.getTenant(), command.getGatewayOrDeviceId());
if (commandHandler != null && commandHandler.getGatewayId() != null) {
// Gateway information set in command handler means a gateway has subscribed for commands for a specific device.
// This information isn't getting set in the message (by the Command Router) and therefore has to be adopted manually here.
command.setGatewayId(commandHandler.getGatewayId());
}
final SpanContext spanContext = TracingHelper.extractSpanContext(tracer, msg);
final SpanContext followsFromSpanContext = commandHandler != null ? commandHandler.getConsumerCreationSpanContext() : null;
final Span currentSpan = CommandContext.createSpan(tracer, command, spanContext, followsFromSpanContext, getClass().getSimpleName());
currentSpan.setTag(MessageHelper.APP_PROPERTY_ADAPTER_INSTANCE_ID, adapterInstanceId);
final CommandContext commandContext = new ProtonBasedCommandContext(command, delivery, currentSpan);
if (commandHandler != null) {
log.trace("using [{}] for received command [{}]", commandHandler, command);
// command.isValid() check not done here - it is to be done in the command handler
commandHandler.handleCommand(commandContext);
} else {
log.info("no command handler found for command [{}]", command);
commandContext.release(new NoConsumerException("no command handler found for command"));
}
}
use of org.eclipse.hono.client.command.CommandContext in project hono by eclipse.
the class ProtonBasedInternalCommandSender method sendCommand.
@Override
public Future<Void> sendCommand(final CommandContext commandContext, final String adapterInstanceId) {
Objects.requireNonNull(commandContext);
Objects.requireNonNull(adapterInstanceId);
return getOrCreateSenderLink(getTargetAddress(adapterInstanceId)).recover(thr -> Future.failedFuture(StatusCodeMapper.toServerError(thr))).compose(sender -> {
final Span span = newChildSpan(commandContext.getTracingContext(), "delegate Command request");
final Command command = commandContext.getCommand();
final Message message = adoptOrCreateMessage(command);
TracingHelper.setDeviceTags(span, command.getTenant(), command.getDeviceId());
if (command.isTargetedAtGateway()) {
MessageHelper.addProperty(message, MessageHelper.APP_PROPERTY_CMD_VIA, command.getGatewayId());
TracingHelper.TAG_GATEWAY_ID.set(span, command.getGatewayId());
}
return sender.sendAndWaitForRawOutcome(message, span);
}).map(delivery -> {
final DeliveryState remoteState = delivery.getRemoteState();
LOG.trace("command [{}] sent to downstream peer; remote state of delivery: {}", commandContext.getCommand(), remoteState);
if (Accepted.class.isInstance(remoteState)) {
commandContext.accept();
} else if (Rejected.class.isInstance(remoteState)) {
final Rejected rejected = (Rejected) remoteState;
commandContext.reject(Optional.ofNullable(rejected.getError()).map(ErrorCondition::getDescription).orElse(null));
} else if (Released.class.isInstance(remoteState)) {
commandContext.release();
} else if (Modified.class.isInstance(remoteState)) {
final Modified modified = (Modified) remoteState;
commandContext.modify(modified.getDeliveryFailed(), modified.getUndeliverableHere());
}
return (Void) null;
}).onFailure(thr -> {
LOG.debug("failed to send command [{}] to downstream peer", commandContext.getCommand(), thr);
if (thr instanceof NoConsumerException) {
TracingHelper.logError(commandContext.getTracingSpan(), "no credit - target adapter instance '" + adapterInstanceId + "' may be offline in which case the device hasn't subscribed again yet");
}
commandContext.release(thr);
});
}
use of org.eclipse.hono.client.command.CommandContext in project hono by eclipse.
the class ProtonBasedInternalCommandConsumerTest method testHandleCommandMessageWithHandlerForGatewayAndSpecificDevice.
/**
* Verifies that the consumer handles a valid message, for which the matching command handler is associated
* with a gateway, by invoking the handler and adopting the gateway identifier in the command object.
*/
@Test
void testHandleCommandMessageWithHandlerForGatewayAndSpecificDevice() {
final String deviceId = "4711";
final String gatewayId = "gw-1";
final String correlationId = "the-correlation-id";
final Message message = ProtonHelper.message("input data");
message.setAddress(String.format("%s/%s/%s", CommandConstants.COMMAND_ENDPOINT, Constants.DEFAULT_TENANT, deviceId));
message.setSubject("doThis");
message.setCorrelationId(correlationId);
final Handler<CommandContext> commandHandler = VertxMockSupport.mockHandler();
commandHandlers.putCommandHandler(Constants.DEFAULT_TENANT, deviceId, gatewayId, commandHandler, context);
internalCommandConsumer.handleCommandMessage(mock(ProtonDelivery.class), message);
final ArgumentCaptor<CommandContext> commandContextCaptor = ArgumentCaptor.forClass(CommandContext.class);
verify(commandHandler).handle(commandContextCaptor.capture());
assertThat(commandContextCaptor.getValue()).isNotNull();
// assert that command is directed at the gateway
assertThat(commandContextCaptor.getValue().getCommand().getGatewayId()).isEqualTo(gatewayId);
assertThat(commandContextCaptor.getValue().getCommand().getDeviceId()).isEqualTo(deviceId);
}
use of org.eclipse.hono.client.command.CommandContext in project hono by eclipse.
the class ProtonBasedInternalCommandConsumerTest method testHandleCommandMessageWithHandlerForGateway.
/**
* Verifies that the consumer handles a valid message, targeted at a gateway, by invoking the matching command
* handler.
*/
@Test
void testHandleCommandMessageWithHandlerForGateway() {
final String deviceId = "4711";
final String gatewayId = "gw-1";
final String correlationId = "the-correlation-id";
final Message message = ProtonHelper.message("input data");
message.setAddress(String.format("%s/%s/%s", CommandConstants.COMMAND_ENDPOINT, Constants.DEFAULT_TENANT, deviceId));
message.setSubject("doThis");
message.setCorrelationId(correlationId);
message.setApplicationProperties(new ApplicationProperties(Collections.singletonMap(MessageHelper.APP_PROPERTY_CMD_VIA, gatewayId)));
final Handler<CommandContext> commandHandler = VertxMockSupport.mockHandler();
commandHandlers.putCommandHandler(Constants.DEFAULT_TENANT, gatewayId, null, commandHandler, context);
internalCommandConsumer.handleCommandMessage(mock(ProtonDelivery.class), message);
final ArgumentCaptor<CommandContext> commandContextCaptor = ArgumentCaptor.forClass(CommandContext.class);
verify(commandHandler).handle(commandContextCaptor.capture());
assertThat(commandContextCaptor.getValue()).isNotNull();
// assert that command is directed at the gateway
assertThat(commandContextCaptor.getValue().getCommand().getGatewayId()).isEqualTo(gatewayId);
assertThat(commandContextCaptor.getValue().getCommand().getDeviceId()).isEqualTo(deviceId);
}
use of org.eclipse.hono.client.command.CommandContext in project hono by eclipse.
the class ProtonBasedInternalCommandConsumerTest method testHandleCommandMessageWithHandlerForDevice.
/**
* Verifies that the consumer handles a valid message by invoking the matching command handler.
*/
@Test
void testHandleCommandMessageWithHandlerForDevice() {
final String deviceId = "4711";
final String correlationId = "the-correlation-id";
final Message message = ProtonHelper.message("input data");
message.setAddress(String.format("%s/%s/%s", CommandConstants.COMMAND_ENDPOINT, Constants.DEFAULT_TENANT, deviceId));
message.setSubject("doThis");
message.setCorrelationId(correlationId);
final Handler<CommandContext> commandHandler = VertxMockSupport.mockHandler();
commandHandlers.putCommandHandler(Constants.DEFAULT_TENANT, deviceId, null, commandHandler, context);
internalCommandConsumer.handleCommandMessage(mock(ProtonDelivery.class), message);
final ArgumentCaptor<CommandContext> commandContextCaptor = ArgumentCaptor.forClass(CommandContext.class);
verify(commandHandler).handle(commandContextCaptor.capture());
assertThat(commandContextCaptor.getValue()).isNotNull();
assertThat(commandContextCaptor.getValue().getCommand().getDeviceId()).isEqualTo(deviceId);
}
Aggregations