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

com.github.dcsolutions.kalinka.pub.plugin.example.MqttMqttJmsMessagePublisher Maven / Gradle / Ivy

/*
 * Copyright [2017] [DCS ] Licensed under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License. You may obtain a
 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable
 * law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 * for the specific language governing permissions and limitations under the License.
 */

package com.github.dcsolutions.kalinka.pub.plugin.example;

import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.activemq.command.Message;
import com.github.dcsolutions.kalinka.pub.publisher.IMessagePublisher;
import com.github.dcsolutions.kalinka.pub.util.HashUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.style.ToStringCreator;
import org.springframework.kafka.core.KafkaTemplate;

/**
 * @author michas 
 *
 * This is an example user-implementation. It matches the topic names and topic-mapping-semantics described in README.md
 *
 */
public class MqttMqttJmsMessagePublisher implements IMessagePublisher {

	private static final Logger LOG = LoggerFactory.getLogger(MqttMqttJmsMessagePublisher.class);

	private static final Pattern REGEX_PATTERN = Pattern.compile("mqtt[\\./](\\S+)[\\./]mqtt[\\./](\\S+).pub");

	private static final String KAFKA_DEST_TOPIC = "{p}.mqtt.mqtt";

	private final int numLogicalPartitions;

	public MqttMqttJmsMessagePublisher(final int numLogicalPartitions) {

		this.numLogicalPartitions = numLogicalPartitions;
	}

	@Override
	public void publish(final Message message, final KafkaTemplate kafkaTemplate) {

		try {
			final byte[] effectivePayload = message.getContent().getData();
			final MessageContainer messageContainer = this.createMessageContainer(message.getDestination().getPhysicalName(), effectivePayload);
			LOG.debug("Will send message={}", messageContainer);
			kafkaTemplate.send(messageContainer.topic, messageContainer.key, messageContainer.content);
		} catch (final Throwable t) {
			LOG.error("Exception occured", t);
		}
	}

	MessageContainer createMessageContainer(final String rawSourceTopic, final byte[] effectivePayload) {

		LOG.debug("Creating MessageContainer for rawSourceTopic={}, effectivePayload={}", rawSourceTopic,
				effectivePayload != null ? new String(effectivePayload) : null);

		final SrcDestId srcDestIds = this.getSourceAndDestId(rawSourceTopic);
		if (srcDestIds == null) {
			throw new IllegalStateException("Could not get sourceId and destId from topic=" + rawSourceTopic);
		}
		final byte[] payload = this.getEnrichedPayload(effectivePayload, srcDestIds.getSrcId());
		final String destTopic = this.getDestTopic(srcDestIds.getSrcId());
		return new MessageContainer(destTopic, srcDestIds.getDestId(), payload);
	}

	String getDestTopic(final String sourceId) {

		final int logicalPartition = HashUtil.hashKey(sourceId, this.numLogicalPartitions);
		final String destTopic = KAFKA_DEST_TOPIC.replace("{p}", String.valueOf(logicalPartition));
		return destTopic;
	}


	SrcDestId getSourceAndDestId(final String rawTopic) {

		final Matcher m = this.getSourceTopicRegex().matcher(rawTopic);
		if (m.find()) {
			return new SrcDestId(m.group(1), m.group(2));
		}
		return null;
	}

	byte[] getEnrichedPayload(final byte[] effectivePayload, final String srcId) {

		final byte[] headerBytes = ("{\"srcId\": \"" + srcId + "\"}").getBytes(StandardCharsets.UTF_8);
		final byte[] header = new byte[64];
		System.arraycopy(headerBytes, 0, header, 0, headerBytes.length);
		final byte[] enriched = new byte[header.length + effectivePayload.length];
		System.arraycopy(header, 0, enriched, 0, header.length);
		System.arraycopy(effectivePayload, 0, enriched, header.length, effectivePayload.length);
		return enriched;
	}

	@Override
	public Pattern getSourceTopicRegex() {

		return REGEX_PATTERN;
	}

	public static class MessageContainer {

		private final String topic;
		private final String key;
		private final byte[] content;

		public MessageContainer(final String topic, final String key, final byte[] content) {
			super();
			this.topic = topic;
			this.key = key;
			this.content = content;
		}

		public String getTopic() {
			return topic;
		}

		public String getKey() {
			return key;
		}

		public byte[] getContent() {
			return content;
		}

		@Override
		public String toString() {
			return new ToStringCreator(this).append("topic", this.topic).append("key", this.key)
					.append("content", this.content != null ? new String(this.content) : null).toString();
		}
	}

	public static class SrcDestId {

		private final String srcId;
		private final String destId;

		public SrcDestId(final String srcId, final String destId) {

			this.srcId = srcId;
			this.destId = destId;
		}

		public String getSrcId() {
			return srcId;
		}

		public String getDestId() {
			return destId;
		}


	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy