Search in sources :

Example 21 with Command

use of org.eclipse.hono.client.command.Command 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);
    });
}
Also used : InternalCommandSender(org.eclipse.hono.client.command.InternalCommandSender) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) Command(org.eclipse.hono.client.command.Command) LoggerFactory(org.slf4j.LoggerFactory) NoConsumerException(org.eclipse.hono.client.NoConsumerException) Modified(org.apache.qpid.proton.amqp.messaging.Modified) StatusCodeMapper(org.eclipse.hono.client.StatusCodeMapper) DeliveryState(org.apache.qpid.proton.amqp.transport.DeliveryState) Message(org.apache.qpid.proton.message.Message) TracingHelper(org.eclipse.hono.tracing.TracingHelper) HonoConnection(org.eclipse.hono.client.HonoConnection) CommandConstants(org.eclipse.hono.util.CommandConstants) Logger(org.slf4j.Logger) CommandContext(org.eclipse.hono.client.command.CommandContext) ProtonHelper(io.vertx.proton.ProtonHelper) MessageHelper(org.eclipse.hono.util.MessageHelper) Released(org.apache.qpid.proton.amqp.messaging.Released) Future(io.vertx.core.Future) Objects(java.util.Objects) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) SenderCachingServiceClient(org.eclipse.hono.client.amqp.SenderCachingServiceClient) Optional(java.util.Optional) Span(io.opentracing.Span) SendMessageSampler(org.eclipse.hono.client.SendMessageSampler) Accepted(org.apache.qpid.proton.amqp.messaging.Accepted) Released(org.apache.qpid.proton.amqp.messaging.Released) Modified(org.apache.qpid.proton.amqp.messaging.Modified) Message(org.apache.qpid.proton.message.Message) DeliveryState(org.apache.qpid.proton.amqp.transport.DeliveryState) Command(org.eclipse.hono.client.command.Command) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) NoConsumerException(org.eclipse.hono.client.NoConsumerException) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) Span(io.opentracing.Span) Accepted(org.apache.qpid.proton.amqp.messaging.Accepted)

Example 22 with Command

use of org.eclipse.hono.client.command.Command in project hono by eclipse.

the class KafkaBasedInternalCommandSender method sendCommand.

@Override
public Future<Void> sendCommand(final CommandContext commandContext, final String adapterInstanceId) {
    Objects.requireNonNull(commandContext);
    Objects.requireNonNull(adapterInstanceId);
    final Command command = commandContext.getCommand();
    if (!(command instanceof KafkaBasedCommand)) {
        commandContext.release();
        log.error("command is not an instance of KafkaBasedCommand");
        throw new IllegalArgumentException("command is not an instance of KafkaBasedCommand");
    }
    final String topicName = getInternalCommandTopic(adapterInstanceId);
    final Span currentSpan = startChildSpan("delegate Command request", topicName, command.getTenant(), command.getDeviceId(), commandContext.getTracingContext());
    return sendAndWaitForOutcome(topicName, command.getTenant(), command.getDeviceId(), command.getPayload(), getHeaders((KafkaBasedCommand) command), currentSpan).onSuccess(v -> commandContext.accept()).onFailure(thr -> commandContext.release(new ServerErrorException(command.getTenant(), HttpURLConnection.HTTP_UNAVAILABLE, "failed to publish command message on internal command topic", thr))).onComplete(ar -> currentSpan.finish());
}
Also used : HttpURLConnection(java.net.HttpURLConnection) InternalCommandSender(org.eclipse.hono.client.command.InternalCommandSender) MessagingKafkaProducerConfigProperties(org.eclipse.hono.client.kafka.producer.MessagingKafkaProducerConfigProperties) Tracer(io.opentracing.Tracer) Command(org.eclipse.hono.client.command.Command) CommandContext(org.eclipse.hono.client.command.CommandContext) ServerErrorException(org.eclipse.hono.client.ServerErrorException) KafkaRecordHelper(org.eclipse.hono.client.kafka.KafkaRecordHelper) Future(io.vertx.core.Future) ArrayList(java.util.ArrayList) Objects(java.util.Objects) HonoTopic(org.eclipse.hono.client.kafka.HonoTopic) List(java.util.List) KafkaProducerFactory(org.eclipse.hono.client.kafka.producer.KafkaProducerFactory) Buffer(io.vertx.core.buffer.Buffer) Optional(java.util.Optional) Span(io.opentracing.Span) KafkaHeader(io.vertx.kafka.client.producer.KafkaHeader) AbstractKafkaBasedMessageSender(org.eclipse.hono.client.kafka.producer.AbstractKafkaBasedMessageSender) Command(org.eclipse.hono.client.command.Command) ServerErrorException(org.eclipse.hono.client.ServerErrorException) Span(io.opentracing.Span)

Example 23 with Command

use of org.eclipse.hono.client.command.Command in project hono by eclipse.

the class ProtocolAdapterMockSupport method newRequestResponseCommand.

private Command newRequestResponseCommand(final String tenantId, final String deviceId, final String name, final String replyToId, final String contentType, final Buffer payload, final MessagingType messagingType) {
    final Command command = newOneWayCommand(tenantId, deviceId, name, contentType, payload);
    when(command.isOneWay()).thenReturn(false);
    when(command.getRequestId()).thenReturn(Commands.encodeRequestIdParameters("correlation-id", replyToId, deviceId, messagingType));
    return command;
}
Also used : Command(org.eclipse.hono.client.command.Command)

Example 24 with Command

use of org.eclipse.hono.client.command.Command 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);
    });
}
Also used : HttpURLConnection(java.net.HttpURLConnection) ProtonConnection(io.vertx.proton.ProtonConnection) ProtonReceiver(io.vertx.proton.ProtonReceiver) LifecycleChange(org.eclipse.hono.notification.deviceregistry.LifecycleChange) DeviceChangeNotification(org.eclipse.hono.notification.deviceregistry.DeviceChangeNotification) Tags(io.opentracing.tag.Tags) ProtonServer(io.vertx.proton.ProtonServer) HonoProtonHelper(org.eclipse.hono.util.HonoProtonHelper) ProcessingOutcome(org.eclipse.hono.service.metric.MetricsTags.ProcessingOutcome) EndpointType(org.eclipse.hono.service.metric.MetricsTags.EndpointType) Modified(org.apache.qpid.proton.amqp.messaging.Modified) DeviceCredentials(org.eclipse.hono.adapter.auth.device.DeviceCredentials) Map(java.util.Map) DeliveryState(org.apache.qpid.proton.amqp.transport.DeliveryState) AuthorizationException(org.eclipse.hono.adapter.AuthorizationException) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) Fields(io.opentracing.log.Fields) AmqpError(org.apache.qpid.proton.amqp.transport.AmqpError) TracingHelper(org.eclipse.hono.tracing.TracingHelper) ProtonSaslAuthenticatorFactory(io.vertx.proton.sasl.ProtonSaslAuthenticatorFactory) AllDevicesOfTenantDeletedNotification(org.eclipse.hono.notification.deviceregistry.AllDevicesOfTenantDeletedNotification) TenantServiceBasedX509Authentication(org.eclipse.hono.adapter.auth.device.TenantServiceBasedX509Authentication) Predicate(java.util.function.Predicate) Collection(java.util.Collection) CommandContext(org.eclipse.hono.client.command.CommandContext) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) ProtonQoS(io.vertx.proton.ProtonQoS) MessageHelper(org.eclipse.hono.util.MessageHelper) Collectors(java.util.stream.Collectors) Future(io.vertx.core.Future) Device(org.eclipse.hono.auth.Device) Objects(java.util.Objects) ErrorCondition(org.apache.qpid.proton.amqp.transport.ErrorCondition) List(java.util.List) QoS(org.eclipse.hono.service.metric.MetricsTags.QoS) TenantTraceSamplingHelper(org.eclipse.hono.tracing.TenantTraceSamplingHelper) CommandConsumer(org.eclipse.hono.client.command.CommandConsumer) Optional(java.util.Optional) Span(io.opentracing.Span) ProtonSender(io.vertx.proton.ProtonSender) NotificationEventBusSupport(org.eclipse.hono.notification.NotificationEventBusSupport) ProtonLink(io.vertx.proton.ProtonLink) Accepted(org.apache.qpid.proton.amqp.messaging.Accepted) ProtonServerOptions(io.vertx.proton.ProtonServerOptions) Rejected(org.apache.qpid.proton.amqp.messaging.Rejected) ConnectionLimitManager(org.eclipse.hono.adapter.limiting.ConnectionLimitManager) Command(org.eclipse.hono.client.command.Command) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) HashMap(java.util.HashMap) ClientErrorException(org.eclipse.hono.client.ClientErrorException) AdapterDisabledException(org.eclipse.hono.adapter.AdapterDisabledException) ServiceInvocationException(org.eclipse.hono.client.ServiceInvocationException) OptionalInt(java.util.OptionalInt) AtomicReference(java.util.concurrent.atomic.AtomicReference) Function(java.util.function.Function) Commands(org.eclipse.hono.client.command.Commands) Constants(org.eclipse.hono.util.Constants) CompositeFuture(io.vertx.core.CompositeFuture) ProtonSession(io.vertx.proton.ProtonSession) Symbol(org.apache.qpid.proton.amqp.Symbol) AdapterConnectionsExceededException(org.eclipse.hono.adapter.AdapterConnectionsExceededException) Target(org.apache.qpid.proton.amqp.transport.Target) UnsignedLong(org.apache.qpid.proton.amqp.UnsignedLong) Message(org.apache.qpid.proton.message.Message) HttpUtils(org.eclipse.hono.service.http.HttpUtils) AsyncResult(io.vertx.core.AsyncResult) CommandConstants(org.eclipse.hono.util.CommandConstants) TenantChangeNotification(org.eclipse.hono.notification.deviceregistry.TenantChangeNotification) Strings(org.eclipse.hono.util.Strings) UsernamePasswordAuthProvider(org.eclipse.hono.adapter.auth.device.UsernamePasswordAuthProvider) 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) ProtonHelper(io.vertx.proton.ProtonHelper) Sample(io.micrometer.core.instrument.Timer.Sample) Released(org.apache.qpid.proton.amqp.messaging.Released) CommandResponse(org.eclipse.hono.client.command.CommandResponse) TenantObject(org.eclipse.hono.util.TenantObject) SpanContext(io.opentracing.SpanContext) Source(org.apache.qpid.proton.amqp.transport.Source) ConnectionAttemptOutcome(org.eclipse.hono.service.metric.MetricsTags.ConnectionAttemptOutcome) MemoryBasedConnectionLimitStrategy(org.eclipse.hono.adapter.limiting.MemoryBasedConnectionLimitStrategy) X509AuthProvider(org.eclipse.hono.adapter.auth.device.X509AuthProvider) Handler(io.vertx.core.Handler) Collections(java.util.Collections) DefaultConnectionLimitManager(org.eclipse.hono.adapter.limiting.DefaultConnectionLimitManager) TenantObject(org.eclipse.hono.util.TenantObject) HashMap(java.util.HashMap) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) ClientErrorException(org.eclipse.hono.client.ClientErrorException) TenantObject(org.eclipse.hono.util.TenantObject) CommandResponse(org.eclipse.hono.client.command.CommandResponse)

Example 25 with Command

use of org.eclipse.hono.client.command.Command in project hono by eclipse.

the class AbstractHonoResource method addCommandToResponse.

/**
 * Adds a command to a CoAP response.
 * <p>
 * This default implementation adds the command name, content format and response URI to the
 * CoAP response options and puts the command's input data (if any) to the response body.
 *
 * @param response The CoAP response.
 * @param commandContext The context containing the command to add.
 * @param currentSpan The Open Tracing span used for tracking the CoAP request.
 */
protected void addCommandToResponse(final Response response, final CommandContext commandContext, final Span currentSpan) {
    final Command command = commandContext.getCommand();
    final OptionSet options = response.getOptions();
    options.addLocationQuery(Constants.HEADER_COMMAND + "=" + command.getName());
    if (command.isOneWay()) {
        options.setLocationPath(CommandConstants.COMMAND_ENDPOINT);
    } else {
        options.setLocationPath(CommandConstants.COMMAND_RESPONSE_ENDPOINT);
    }
    currentSpan.setTag(Constants.HEADER_COMMAND, command.getName());
    LOG.debug("adding command [name: {}, request-id: {}] to response for device [tenant-id: {}, device-id: {}]", command.getName(), command.getRequestId(), command.getTenant(), command.getGatewayOrDeviceId());
    commandContext.getTracingSpan().log("forwarding command to device in CoAP response");
    if (command.isTargetedAtGateway()) {
        options.addLocationPath(command.getTenant());
        options.addLocationPath(command.getDeviceId());
        currentSpan.setTag(Constants.HEADER_COMMAND_TARGET_DEVICE, command.getDeviceId());
    }
    if (!command.isOneWay()) {
        options.addLocationPath(command.getRequestId());
        currentSpan.setTag(Constants.HEADER_COMMAND_REQUEST_ID, command.getRequestId());
    }
    final int formatCode = MediaTypeRegistry.parse(command.getContentType());
    if (formatCode != MediaTypeRegistry.UNDEFINED) {
        options.setContentFormat(formatCode);
    } else {
        currentSpan.log("ignoring unknown content type [" + command.getContentType() + "] of command");
    }
    Optional.ofNullable(command.getPayload()).ifPresent(b -> response.setPayload(b.getBytes()));
}
Also used : Command(org.eclipse.hono.client.command.Command) OptionSet(org.eclipse.californium.core.coap.OptionSet)

Aggregations

Command (org.eclipse.hono.client.command.Command)34 Span (io.opentracing.Span)23 Future (io.vertx.core.Future)23 HttpURLConnection (java.net.HttpURLConnection)22 ServerErrorException (org.eclipse.hono.client.ServerErrorException)22 CommandContext (org.eclipse.hono.client.command.CommandContext)22 Map (java.util.Map)19 Objects (java.util.Objects)19 Optional (java.util.Optional)19 Device (org.eclipse.hono.auth.Device)19 Constants (org.eclipse.hono.util.Constants)19 Buffer (io.vertx.core.buffer.Buffer)18 TracingHelper (org.eclipse.hono.tracing.TracingHelper)18 SpanContext (io.opentracing.SpanContext)17 Tags (io.opentracing.tag.Tags)17 Handler (io.vertx.core.Handler)17 ClientErrorException (org.eclipse.hono.client.ClientErrorException)17 MessageHelper (org.eclipse.hono.util.MessageHelper)17 TenantObject (org.eclipse.hono.util.TenantObject)17 List (java.util.List)16