All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.hono.adapter.kura.KuraProtocolAdapter Maven / Gradle / Ivy

/**
 * Copyright (c) 2017, 2018 Contributors to the Eclipse Foundation
 *
 * See the NOTICE file(s) distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 1.0 which is available at
 * https://www.eclipse.org/legal/epl-v10.html
 *
 * SPDX-License-Identifier: EPL-1.0
 */

package org.eclipse.hono.adapter.kura;

import java.net.HttpURLConnection;
import java.util.Arrays;

import org.eclipse.hono.adapter.mqtt.AbstractVertxBasedMqttProtocolAdapter;
import org.eclipse.hono.adapter.mqtt.MqttContext;
import org.eclipse.hono.client.ClientErrorException;
import org.eclipse.hono.util.Constants;
import org.eclipse.hono.util.EventConstants;
import org.eclipse.hono.util.ResourceIdentifier;
import org.eclipse.hono.util.TelemetryConstants;

import io.netty.handler.codec.mqtt.MqttQoS;
import io.vertx.core.Future;

/**
 * A Vert.x based Hono protocol adapter for publishing messages to Hono's Telemetry and Event APIs from
 * Eclipse Kura gateways.
 */
public final class KuraProtocolAdapter extends AbstractVertxBasedMqttProtocolAdapter {

    /**
     * Gets this adapter's type name.
     * 
     * @return {@link Constants#PROTOCOL_ADAPTER_TYPE_KURA}
     */
    @Override
    protected String getTypeName() {
        return Constants.PROTOCOL_ADAPTER_TYPE_KURA;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected Future onPublishedMessage(final MqttContext ctx) {

        return mapTopic(ctx)
                .recover(t -> {
                    LOG.debug("discarding message [topic: {}] from device: {}", ctx.message().topicName(), t.getMessage());
                    return Future.failedFuture(t);
                }).compose(address -> uploadMessage(ctx, address, ctx.message().payload()));
    }

    Future mapTopic(final MqttContext ctx) {

        final Future result = Future.future();
        try {
            final ResourceIdentifier topic = ResourceIdentifier.fromString(ctx.message().topicName());
            ResourceIdentifier mappedTopic = null;

            if (getConfig().getControlPrefix().equals(topic.getEndpoint())) {

                // this is a "control" message
                ctx.setContentType(getConfig().getCtrlMsgContentType());
                final String[] mappedPath = Arrays.copyOf(topic.getResourcePath(), topic.getResourcePath().length);
                mappedPath[0] = getEndpoint(ctx.message().qosLevel());
                mappedTopic = ResourceIdentifier.fromPath(mappedPath);

            } else {

                // map "data" messages based on QoS
                ctx.setContentType(getConfig().getDataMsgContentType());
                final String[] mappedPath = new String[topic.getResourcePath().length + 1];
                System.arraycopy(topic.getResourcePath(), 0, mappedPath, 1, topic.getResourcePath().length);
                mappedPath[0] = getEndpoint(ctx.message().qosLevel());
                mappedTopic = ResourceIdentifier.fromPath(mappedPath);
            }

            if (mappedTopic.getResourcePath().length < 3) {
                // topic does not contain account_name and client_id
                result.fail(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "topic does not comply with Kura format"));
            } else {
                LOG.debug("mapped Kura message [topic: {}, QoS: {}] to Hono message [to: {}, device_id: {}, content-type: {}]",
                        topic, ctx.message().qosLevel(), mappedTopic.getBasePath(), mappedTopic.getResourceId(), ctx.contentType());
                result.complete(mappedTopic);
            }
        } catch (final IllegalArgumentException e) {
            result.fail(new ClientErrorException(HttpURLConnection.HTTP_BAD_REQUEST, "malformed topic name"));
        }
        return result;
    }

    private static String getEndpoint(final MqttQoS level) {

        switch(level) {
        case AT_MOST_ONCE:
            return TelemetryConstants.TELEMETRY_ENDPOINT;
        default:
            return EventConstants.EVENT_ENDPOINT;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy