/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 io.jafka.server;
import io.jafka.consumer.Consumer;
import io.jafka.consumer.ConsumerConfig;
import io.jafka.consumer.ConsumerConnector;
import io.jafka.consumer.MessageStream;
import io.jafka.consumer.TopicEventHandler;
import io.jafka.consumer.ZookeeperTopicEventWatcher;
import io.jafka.message.Message;
import io.jafka.producer.Producer;
import io.jafka.producer.ProducerConfig;
import io.jafka.producer.serializer.MessageEncoders;
import io.jafka.utils.Closer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* @author adyliu (imxylz@gmail.com)
* @since 1.0
*/
public class EmbeddedConsumer implements TopicEventHandler<String> {
private final ConsumerConfig consumerConfig;
private final ServerStartable serverStartable;
//
private final List<String> whiteListTopics;
private final List<String> blackListTopics;
private final Producer<Void, Message> producer;
//
private ZookeeperTopicEventWatcher topicEventWatcher;
private ConsumerConnector consumerConnector;
private List<MirroringThread> threadList = new ArrayList<MirroringThread>();
private static final Logger logger = LoggerFactory.getLogger(EmbeddedConsumer.class);
private List<String> mirrorTopics = new ArrayList<String>();
/**
* @param consumerConfig the inner consumer config
* @param producerConfig the producer config
* @param serverStartable server instance
*/
public EmbeddedConsumer(ConsumerConfig consumerConfig, ProducerConfig producerConfig, ServerStartable serverStartable) {
this.consumerConfig = consumerConfig;
this.serverStartable = serverStartable;
//
this.whiteListTopics = Arrays.asList(consumerConfig.getMirrorTopicsWhitelist().split(","));
this.blackListTopics = Arrays.asList(consumerConfig.getMirrorTopicsBlackList().split(","));
this.producer = new Producer<Void, Message>(producerConfig);
}
/**
*
*/
public void startup() {
logger.info("staring up embedded consumer");
topicEventWatcher = new ZookeeperTopicEventWatcher(consumerConfig, this, serverStartable);
}
/**
*
*/
public void shutdown() {
if (topicEventWatcher != null) {
Closer.closeQuietly(topicEventWatcher);
}
if (consumerConnector != null) {
Closer.closeQuietly(consumerConnector);
}
for (MirroringThread thread : threadList) {
thread.close();
}
producer.close();
}
public void handleTopicEvent(List<String> allTopics) {
List<String> newMirrorTopics = new ArrayList<String>();
List<String> addedTopics = new ArrayList<String>();
List<String> deletedTopics = new ArrayList<String>();
final Map<String, Integer> topicCountMap = new LinkedHashMap<String, Integer>();
for (String topic : allTopics) {
boolean newTopic = false;
if (whiteListTopics.isEmpty()) {
newTopic = whiteListTopics.contains(topic);
} else {
newTopic = !blackListTopics.contains(topic);
}
if (newTopic) {
newMirrorTopics.add(topic);
topicCountMap.put(topic, consumerConfig.getMirrorConsumerNumThreads());
if (!mirrorTopics.contains(topic)) {
addedTopics.add(topic);
}
}
}
//
//
for (String topic : mirrorTopics) {
if (!newMirrorTopics.contains(topic)) {
deletedTopics.add(topic);
}
}
//
mirrorTopics = newMirrorTopics;
//
if (!addedTopics.isEmpty() || !deletedTopics.isEmpty()) {
startNewConsumerThreads(topicCountMap);
}
}
private void startNewConsumerThreads(Map<String, Integer> topicCountMap) {
if (topicCountMap.isEmpty()) return;
if (consumerConnector != null) {
Closer.closeQuietly(consumerConnector);
}
for (MirroringThread thread : threadList) {
thread.close();
}
threadList.clear();
consumerConnector = Consumer.create(consumerConfig);
Map<String, List<MessageStream<Message>>> streams = consumerConnector.createMessageStreams(topicCountMap, new MessageEncoders());
for (Map.Entry<String, List<MessageStream<Message>>> e : streams.entrySet()) {
int i = 0;
for (MessageStream<Message> stream : e.getValue()) {
threadList.add(new MirroringThread(stream, e.getKey(), i++, producer));
}
}
for (MirroringThread t : threadList) {
t.start();
}
}
}