Search in sources :

Example 1 with MappedMessage

use of org.eclipse.hono.adapter.mqtt.MappedMessage in project hono by eclipse.

the class HttpBasedMessageMapping method mapDownstreamMessage.

/**
 * {@inheritDoc}
 * <p>
 * This implementation tries to look up the URL of the service endpoint to invoke in the
 * adapter's <em>mapperEndpoints</em> using the value of the registration assertion's
 * <em>mapper</em> property as the key.
 * If a mapping endpoint configuration is found, an HTTP GET request is sent to the endpoint
 * containing the original message's
 * <ul>
 * <li>payload in the request body,</li>
 * <li>content type in the HTTP content-type header,</li>
 * <li>topic name in the {@value MessageHelper#APP_PROPERTY_ORIG_ADDRESS} header and</li>
 * <li>all properties from the registration assertion as headers.</li>
 * </ul>
 *
 * @return A future indicating the mapping result.
 *         The future will be succeeded with the original unaltered message if no mapping
 *         URL could be found. The future will be succeeded with the message contained in the
 *         response body if the returned status code is 200.
 *         Otherwise, the future will be failed with a {@link ServerErrorException}.
 */
@Override
public Future<MappedMessage> mapDownstreamMessage(final MqttContext ctx, final ResourceIdentifier targetAddress, final RegistrationAssertion registrationInfo) {
    Objects.requireNonNull(ctx);
    Objects.requireNonNull(registrationInfo);
    final Promise<MappedMessage> result = Promise.promise();
    final String mapper = registrationInfo.getDownstreamMessageMapper();
    if (Strings.isNullOrEmpty(mapper)) {
        LOG.debug("no payload mapping configured for {}", ctx.authenticatedDevice());
        result.complete(unmodifiedMappedMessage(ctx, targetAddress));
    } else {
        final MapperEndpoint mapperEndpoint = mqttProtocolAdapterProperties.getMapperEndpoint(mapper);
        if (mapperEndpoint == null) {
            LOG.debug("no mapping endpoint [name: {}] found for {}", mapper, ctx.authenticatedDevice());
            result.complete(unmodifiedMappedMessage(ctx, targetAddress));
        } else {
            mapDownstreamMessageRequest(ctx, targetAddress, registrationInfo, mapperEndpoint, result);
        }
    }
    return result.future();
}
Also used : MapperEndpoint(org.eclipse.hono.config.MapperEndpoint) MappedMessage(org.eclipse.hono.adapter.mqtt.MappedMessage)

Example 2 with MappedMessage

use of org.eclipse.hono.adapter.mqtt.MappedMessage in project hono by eclipse.

the class HttpBasedMessageMapping method mapDownstreamMessageRequest.

private void mapDownstreamMessageRequest(final MqttContext ctx, final ResourceIdentifier targetAddress, final RegistrationAssertion registrationInfo, final MapperEndpoint mapperEndpoint, final Handler<AsyncResult<MappedMessage>> resultHandler) {
    final MultiMap headers = MultiMap.caseInsensitiveMultiMap();
    JsonObject.mapFrom(registrationInfo).forEach(property -> {
        final Object value = property.getValue();
        if (value instanceof String) {
            // prevent strings from being enclosed in quotes
            headers.add(property.getKey(), (String) value);
        } else {
            headers.add(property.getKey(), Json.encode(value));
        }
    });
    headers.add(MessageHelper.APP_PROPERTY_ORIG_ADDRESS, ctx.message().topicName());
    if (ctx.contentType() != null) {
        headers.add(HttpHeaders.CONTENT_TYPE.toString(), ctx.contentType());
    }
    final Promise<MappedMessage> result = Promise.promise();
    webClient.post(mapperEndpoint.getPort(), mapperEndpoint.getHost(), mapperEndpoint.getUri()).putHeaders(headers).ssl(mapperEndpoint.isTlsEnabled()).sendBuffer(ctx.message().payload(), httpResponseAsyncResult -> {
        if (httpResponseAsyncResult.failed()) {
            LOG.debug("failed to map message [origin: {}] using mapping service [host: {}, port: {}, URI: {}]", ctx.authenticatedDevice(), mapperEndpoint.getHost(), mapperEndpoint.getPort(), mapperEndpoint.getUri(), httpResponseAsyncResult.cause());
            result.fail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, httpResponseAsyncResult.cause()));
        } else {
            final HttpResponse<Buffer> httpResponse = httpResponseAsyncResult.result();
            if (httpResponse.statusCode() == HttpURLConnection.HTTP_OK) {
                final Map<String, String> additionalProperties = new HashMap<>();
                httpResponse.headers().forEach(entry -> additionalProperties.put(entry.getKey(), entry.getValue()));
                final String mappedDeviceId = Optional.ofNullable(additionalProperties.remove(MessageHelper.APP_PROPERTY_DEVICE_ID)).map(id -> {
                    LOG.debug("original {} has been mapped to [device-id: {}]", ctx.authenticatedDevice(), id);
                    return id;
                }).orElseGet(() -> targetAddress.getResourceId());
                result.complete(new MappedMessage(ResourceIdentifier.from(targetAddress.getEndpoint(), targetAddress.getTenantId(), mappedDeviceId), httpResponse.bodyAsBuffer(), additionalProperties));
            } else {
                LOG.debug("mapping service [host: {}, port: {}, URI: {}] returned unexpected status code: {}", mapperEndpoint.getHost(), mapperEndpoint.getPort(), mapperEndpoint.getUri(), httpResponse.statusCode());
                result.fail(new ServerErrorException(HttpURLConnection.HTTP_UNAVAILABLE, "could not invoke configured mapping service"));
            }
        }
        resultHandler.handle(result.future());
    });
}
Also used : Buffer(io.vertx.core.buffer.Buffer) HttpURLConnection(java.net.HttpURLConnection) Json(io.vertx.core.json.Json) HttpResponse(io.vertx.ext.web.client.HttpResponse) WebClient(io.vertx.ext.web.client.WebClient) Command(org.eclipse.hono.client.command.Command) LoggerFactory(org.slf4j.LoggerFactory) MultiMap(io.vertx.core.MultiMap) HashMap(java.util.HashMap) Map(java.util.Map) MqttContext(org.eclipse.hono.adapter.mqtt.MqttContext) ResourceIdentifier(org.eclipse.hono.util.ResourceIdentifier) JsonObject(io.vertx.core.json.JsonObject) MappedMessage(org.eclipse.hono.adapter.mqtt.MappedMessage) AsyncResult(io.vertx.core.AsyncResult) Strings(org.eclipse.hono.util.Strings) Logger(org.slf4j.Logger) MapperEndpoint(org.eclipse.hono.config.MapperEndpoint) Promise(io.vertx.core.Promise) ServerErrorException(org.eclipse.hono.client.ServerErrorException) HttpHeaders(io.vertx.core.http.HttpHeaders) RegistrationAssertion(org.eclipse.hono.util.RegistrationAssertion) MessageHelper(org.eclipse.hono.util.MessageHelper) Future(io.vertx.core.Future) Objects(java.util.Objects) Buffer(io.vertx.core.buffer.Buffer) MqttProtocolAdapterProperties(org.eclipse.hono.adapter.mqtt.MqttProtocolAdapterProperties) Optional(java.util.Optional) Handler(io.vertx.core.Handler) MessageMapping(org.eclipse.hono.adapter.mqtt.MessageMapping) MultiMap(io.vertx.core.MultiMap) MappedMessage(org.eclipse.hono.adapter.mqtt.MappedMessage) HashMap(java.util.HashMap) JsonObject(io.vertx.core.json.JsonObject) ServerErrorException(org.eclipse.hono.client.ServerErrorException)

Aggregations

MappedMessage (org.eclipse.hono.adapter.mqtt.MappedMessage)2 MapperEndpoint (org.eclipse.hono.config.MapperEndpoint)2 AsyncResult (io.vertx.core.AsyncResult)1 Future (io.vertx.core.Future)1 Handler (io.vertx.core.Handler)1 MultiMap (io.vertx.core.MultiMap)1 Promise (io.vertx.core.Promise)1 Buffer (io.vertx.core.buffer.Buffer)1 HttpHeaders (io.vertx.core.http.HttpHeaders)1 Json (io.vertx.core.json.Json)1 JsonObject (io.vertx.core.json.JsonObject)1 HttpResponse (io.vertx.ext.web.client.HttpResponse)1 WebClient (io.vertx.ext.web.client.WebClient)1 HttpURLConnection (java.net.HttpURLConnection)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 Objects (java.util.Objects)1 Optional (java.util.Optional)1 MessageMapping (org.eclipse.hono.adapter.mqtt.MessageMapping)1 MqttContext (org.eclipse.hono.adapter.mqtt.MqttContext)1