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

org.eclipse.ditto.connectivity.service.mapping.AbstractMessageMapper Maven / Gradle / Ivy

/*
 * Copyright (c) 2019 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 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0
 *
 * SPDX-License-Identifier: EPL-2.0
 */
package org.eclipse.ditto.connectivity.service.mapping;

import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;

import org.eclipse.ditto.base.model.common.CharsetDeterminer;
import org.eclipse.ditto.base.model.headers.DittoHeaders;
import org.eclipse.ditto.connectivity.api.ExternalMessage;
import org.eclipse.ditto.connectivity.model.Connection;
import org.eclipse.ditto.connectivity.model.MessageMappingFailedException;
import org.eclipse.ditto.connectivity.service.config.ConnectivityConfig;
import org.eclipse.ditto.connectivity.service.config.mapping.MappingConfig;
import org.eclipse.ditto.protocol.Adaptable;
import org.eclipse.ditto.protocol.TopicPath;

import com.typesafe.config.Config;

import akka.actor.ActorSystem;

/**
 * Abstract implementation of {@link MessageMapper} which adds an id field and also its initialization from mapping
 * configuration (id is not passed as constructor argument because the mappers are created by reflection).
 */
public abstract class AbstractMessageMapper implements MessageMapper {

    protected final ActorSystem actorSystem;
    protected final Config config;

    private String id;
    private Map incomingConditions;
    private Map outgoingConditions;
    private Collection contentTypeBlocklist;

    protected AbstractMessageMapper(final ActorSystem actorSystem, final Config config) {
        this.actorSystem = actorSystem;
        this.config = config;
    }

    protected AbstractMessageMapper(final AbstractMessageMapper copyFromMapper) {
        this.actorSystem = copyFromMapper.actorSystem;
        this.config = copyFromMapper.config;
        this.id = copyFromMapper.getId();
        this.incomingConditions = copyFromMapper.getIncomingConditions();
        this.outgoingConditions = copyFromMapper.getOutgoingConditions();
        this.contentTypeBlocklist = copyFromMapper.getContentTypeBlocklist();
    }

    @Override
    public String getId() {
        return id;
    }

    @Override
    public Map getIncomingConditions() {
        return incomingConditions;
    }

    @Override
    public Map getOutgoingConditions() {
        return outgoingConditions;
    }

    @Override
    public Collection getContentTypeBlocklist() {
        return contentTypeBlocklist;
    }

    @Override
    public final void configure(final Connection connection,
            final ConnectivityConfig connectivityConfig,
            final MessageMapperConfiguration configuration,
            final ActorSystem actorSystem) {

        this.id = configuration.getId();
        this.incomingConditions = configuration.getIncomingConditions();
        this.outgoingConditions = configuration.getOutgoingConditions();
        this.contentTypeBlocklist = configuration.getContentTypeBlocklist();
        final MappingConfig mappingConfig = connectivityConfig.getMappingConfig();
        doConfigure(connection, mappingConfig, configuration);
    }

    /**
     * Applies the mapper specific configuration.
     *
     * @param connection the connection to apply the mapping for.
     * @param mappingConfig the service configuration for the mapping.
     * @param configuration the mapper specific configuration configured in scope of a single connection.
     */
    protected void doConfigure(final Connection connection, final MappingConfig mappingConfig,
            final MessageMapperConfiguration configuration) {
        // noop default
    }

    /**
     * Extracts the payload of the passed in {@code message} as string.
     *
     * @param message the external message to extract the payload from.
     * @return the payload of the passed in {@code message} as string
     * @throws MessageMappingFailedException if no payload was present or if it was empty.
     */
    protected static String extractPayloadAsString(final ExternalMessage message) {
        final Optional payload;
        if (message.isTextMessage()) {
            payload = message.getTextPayload();
        } else if (message.isBytesMessage()) {
            final Charset charset = determineCharset(message.getHeaders());
            payload = message.getBytePayload().map(charset::decode).map(CharBuffer::toString);
        } else {
            payload = Optional.empty();
        }

        return payload.filter(s -> !s.isEmpty()).orElseThrow(() ->
                MessageMappingFailedException.newBuilder(message.findContentType().orElse(""))
                        .description(
                                "As payload was absent or empty, please make sure to send payload in your messages.")
                        .dittoHeaders(DittoHeaders.of(message.getHeaders()))
                        .build());
    }

    protected static Charset determineCharset(final Map messageHeaders) {
        return CharsetDeterminer.getInstance().apply(messageHeaders.get(ExternalMessage.CONTENT_TYPE_HEADER));
    }

    protected static boolean isResponse(final Adaptable adaptable) {
        final var payload = adaptable.getPayload();
        final var httpStatus = payload.getHttpStatus();
        return httpStatus.isPresent();
    }

    protected static boolean isError(final Adaptable adaptable) {
        final var topicPath = adaptable.getTopicPath();
        return topicPath.isCriterion(TopicPath.Criterion.ERRORS);
    }

    protected static boolean isLiveSignal(final Adaptable adaptable) {
        return adaptable.getTopicPath().isChannel(TopicPath.Channel.LIVE);
    }

    @Override
    public String toString() {
        return "id=" + id +
            ", incomingConditions=" + incomingConditions +
            ", outgoingConditions=" + outgoingConditions +
            ", contentTypeBlocklist=" + contentTypeBlocklist;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy