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

org.atmosphere.kafka.KafkaBroadcaster Maven / Gradle / Ivy

/*
 * Copyright 2015 Async-IO.org
 *
 * 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 org.atmosphere.kafka;

import kafka.consumer.Consumer;
import kafka.consumer.ConsumerConfig;
import kafka.consumer.ConsumerIterator;
import kafka.consumer.KafkaStream;
import kafka.javaapi.consumer.ConsumerConnector;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.Serializer;
import org.apache.kafka.common.serialization.StringSerializer;
import org.atmosphere.config.managed.ManagedAtmosphereHandler;
import org.atmosphere.cpr.AtmosphereConfig;
import org.atmosphere.cpr.AtmosphereFramework;
import org.atmosphere.cpr.Broadcaster;
import org.atmosphere.util.AbstractBroadcasterProxy;
import org.atmosphere.util.ExecutorsFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * Kafka Support via a {@link Broadcaster}
 *
 * @author Jeanfrancois Arcand.
 */
public class KafkaBroadcaster extends AbstractBroadcasterProxy {

    private final Logger logger = LoggerFactory.getLogger(KafkaBroadcaster.class);

    public final static String PROPERTIES_FILE = "org.atmosphere.kafka.propertiesFile";
    private String topic;

    private KafkaProducer producer;
    private ConsumerConnector consumer;
    private final Serializer stringSerializer = new StringSerializer();
    private Map topicCountMap;
    private Map>> consumerMap;

    @Override
    public Broadcaster initialize(String id, URI uri, final AtmosphereConfig config) {
        super.initialize(id, uri, config);

        topic = id.equals(ROOT_MASTER) ? "atmosphere" : id.replaceAll("[^a-zA-Z0-9\\s]", "");

        // We are thread-safe
        producer = (KafkaProducer) config.properties().get(KafkaProducer.class.getName());
        consumer = (ConsumerConnector) config.properties().get(ConsumerConnector.class.getName());
        topicCountMap = (Map) config.properties().get("topicCountMap");

        if (producer == null) {
            String load = config.getInitParameter(PROPERTIES_FILE, null);
            Properties props = new Properties();
            if (load == null) {
                props.put("bootstrap.servers", "10.0.1.10:9092");
                props.put("zk.connect", "127.0.0.1:9092");
                props.put("group.id", "kafka.atmosphere");
                props.put("partition.assignment.strategy", "roundrobin");
                props.put("zookeeper.connect", "localhost:2181");
            } else {
                try {
                    props.load(config.getServletContext().getResourceAsStream(load));
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

            producer = new KafkaProducer(props, stringSerializer, stringSerializer);
            consumer = Consumer.createJavaConsumerConnector(new ConsumerConfig(props));
            topicCountMap = new HashMap();

            config.properties().put("producer", producer);
            config.properties().put(ConsumerConnector.class.getName(), consumer);
            config.properties().put("topicCountMap", topicCountMap);
        }

        topicCountMap.put(topic, new Integer(1));

        config.startupHook(new AtmosphereConfig.StartupHook() {

            @Override
            public void started(AtmosphereFramework framework) {
                if (config.properties().get("started") != null) return;

                config.properties().put("started", "true");
                consumerMap = consumer.createMessageStreams(topicCountMap);
                for (final String t : topicCountMap.keySet()) {
                    ExecutorsFactory.getMessageDispatcher(config, "kafka").execute(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                KafkaStream stream = consumerMap.get(t).get(0);
                                ConsumerIterator it = stream.iterator();
                                String message;
                                while (it.hasNext()) {
                                    message = new String(it.next().message());

                                    logger.trace("{} incomingBroadcast {}", t, message);
                                    broadcastReceivedMessage(message);
                                }
                            } catch (Exception ex) {
                                if (InterruptedException.class.isAssignableFrom(ex.getClass())) {
                                    logger.trace("", ex);
                                } else {
                                    logger.warn("", ex);
                                }
                            }
                        }
                    });
                }
            }
        });

        return this;
    }

    @Override
    public void incomingBroadcast() {
    }

    @Override
    public void outgoingBroadcast(Object message) {
        logger.trace("{} outgoingBroadcast {}", topic, message);

        // TODO: Prevent message round trip.

        if (ManagedAtmosphereHandler.Managed.class.isAssignableFrom(message.getClass())) {
            message = ManagedAtmosphereHandler.Managed.class.cast(message).object();
        }

        producer.send(new ProducerRecord(topic, message));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy