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

forklift.connectors.KafkaSerializer Maven / Gradle / Ivy

package forklift.connectors;

import forklift.consumer.parser.KeyValueParser;
import forklift.producers.KafkaForkliftProducer;
import forklift.source.SourceI;
import forklift.source.sources.GroupedTopicSource;
import forklift.source.sources.RoleInputSource;
import forklift.source.sources.QueueSource;
import forklift.source.sources.TopicSource;

import org.apache.avro.Schema;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericRecord;
import org.apache.kafka.common.serialization.Deserializer;
import org.apache.kafka.common.serialization.Serializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;

public class KafkaSerializer implements ForkliftSerializer {
    private static final Logger log = LoggerFactory.getLogger(KafkaSerializer.class);

    private KafkaConnector connector;
    private Serializer serializer;
    private Deserializer deserializer;

    public final static String SCHEMA_FIELD_NAME_VALUE = "forkliftValue";
    public final static String SCHEMA_FIELD_NAME_PROPERTIES = "forkliftProperties";
    public static final Schema FORKLIFT_SCHEMA = readSchemaFromClasspath("schemas/ForkliftMessage.avsc");
    public static final String SCHEMA_FIELD_VALUE_PROPERTIES =
                    "{\"name\":\"forkliftProperties\",\"type\":\"string\",\"default\":\"\"," +
                    "\"doc\":\"Properties added to support forklift interfaces. Format is key,value entries delimited with new lines\"}";

    private static Schema readSchemaFromClasspath(String path) {
        Schema.Parser parser = new Schema.Parser();
        try {
            return parser.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream(path));
        } catch (Exception e) {
            log.error("Couldn't parse forklift schema", e);
        }
        return null;
    }

    public KafkaSerializer(KafkaConnector connector, Serializer serializer, Deserializer deserializer) {
        this.connector = connector;
        this.serializer = serializer;
        this.deserializer = deserializer;
    }

    @Override
    public byte[] serializeForSource(SourceI source, Object o) {
        final String topicName = source
            .apply(QueueSource.class, queue -> queue.getName())
            .apply(TopicSource.class, topic -> topic.getName())
            .apply(GroupedTopicSource.class, topic -> topic.getName())
            .apply(RoleInputSource.class, roleSource -> connector.mapRoleInputSource(roleSource).getName())
            .elseUnsupportedError();

        if (o instanceof String) {
            GenericRecord avroRecord = new GenericData.Record(FORKLIFT_SCHEMA);
            avroRecord.put(SCHEMA_FIELD_NAME_VALUE, (String) o);
            avroRecord.put(SCHEMA_FIELD_NAME_PROPERTIES, "");

            o = avroRecord;
        }
        return serializer.serialize(topicName, o);
    }

    @Override
    public  T deserializeForSource(SourceI source, byte[] bytes) {
        final String topicName = source
            .apply(QueueSource.class, queue -> queue.getName())
            .apply(TopicSource.class, topic -> topic.getName())
            .apply(GroupedTopicSource.class, topic -> topic.getName())
            .apply(RoleInputSource.class, roleSource -> connector.mapRoleInputSource(roleSource).getName())
            .elseUnsupportedError();

        return (T) extractMessageFromRecord(deserializer.deserialize(topicName, bytes), null);
    }

    /**
     * A utility for pulling the message and properties out of a record deserialized
     * off of Kafka.
     *
     * @param  the type of the record value
     * @param recordValue the value of the record to extract from
     * @param properties the map to add extracted properties to, or null
     *     if no properties are needed
     * @return the message stored in the record value
     */
    public static  String extractMessageFromRecord(T recordValue, Map properties) {
        Object value = null;
        if (recordValue instanceof GenericRecord) {
            GenericRecord genericRecord = (GenericRecord) recordValue;
            if (properties != null) {
                Object messageProperties = genericRecord.get(SCHEMA_FIELD_NAME_PROPERTIES);
                if (messageProperties != null) {
                    properties.putAll(KeyValueParser.parse(messageProperties.toString()));
                }
            }

            value = genericRecord.get(KafkaSerializer.SCHEMA_FIELD_NAME_VALUE);
            //If the value is null, this is most likely an avro object
            if (value == null) {
                String jsonValue = genericRecord.toString();
                value = jsonValue != null && jsonValue.startsWith("{") ? jsonValue : null;
            }
        }
        return value == null?null:value.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy