/** * 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.producer.async; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import io.jafka.api.ProducerRequest; import io.jafka.message.ByteBufferMessageSet; import io.jafka.message.CompressionCodec; import io.jafka.message.Message; import io.jafka.producer.ProducerConfig; import io.jafka.producer.SyncProducer; import io.jafka.producer.serializer.Encoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author adyliu (imxylz@gmail.com) * @since 1.0 */ public class DefaultEventHandler<T> implements EventHandler<T> { private final CallbackHandler<T> callbackHandler; private final Set<String> compressedTopics; private final CompressionCodec codec; private final Logger logger = LoggerFactory.getLogger(DefaultEventHandler.class); private final int numRetries; public DefaultEventHandler(ProducerConfig producerConfig, CallbackHandler<T> callbackHandler) { this.callbackHandler = callbackHandler; this.compressedTopics = new HashSet<String>(producerConfig.getCompressedTopics()); this.codec = producerConfig.getCompressionCodec(); this.numRetries = producerConfig.getNumRetries(); } public void init(Properties properties) { } public void handle(List<QueueItem<T>> events, SyncProducer producer, Encoder<T> encoder) { List<QueueItem<T>> processedEvents = events; if (this.callbackHandler != null) { processedEvents = this.callbackHandler.beforeSendingData(events); } send(collate(processedEvents, encoder), producer); } private void send(List<ProducerRequest> produces, SyncProducer syncProducer) { if (produces.isEmpty()) { return; } final int maxAttempts = 1 + numRetries; for (int i = 0; i < maxAttempts; i++) { try { syncProducer.multiSend(produces); break; } catch (RuntimeException e) { logger.warn("error sending message, attempts times: " + i, e); if (i == maxAttempts - 1) { throw e; } } } } private List<ProducerRequest> collate(List<QueueItem<T>> events, Encoder<T> encoder) { if(events == null || events.isEmpty()){ return Collections.emptyList(); } final Map<String, Map<Integer, List<Message>>> topicPartitionData = new HashMap<String, Map<Integer, List<Message>>>(); for (QueueItem<T> event : events) { Map<Integer, List<Message>> partitionData = topicPartitionData.get(event.topic); if (partitionData == null) { partitionData = new HashMap<Integer, List<Message>>(); topicPartitionData.put(event.topic, partitionData); } List<Message> data = partitionData.get(event.partition); if (data == null) { data = new ArrayList<Message>(); partitionData.put(event.partition, data); } data.add(encoder.toMessage(event.data)); } // final List<ProducerRequest> requests = new ArrayList<ProducerRequest>(); for (Map.Entry<String, Map<Integer, List<Message>>> e : topicPartitionData.entrySet()) { final String topic = e.getKey(); for (Map.Entry<Integer, List<Message>> pd : e.getValue().entrySet()) { final Integer partition = pd.getKey(); requests.add(new ProducerRequest(topic, partition, convert(topic, pd.getValue()))); } } return requests; } private ByteBufferMessageSet convert(String topic, List<Message> messages) { //compress condition: if (codec != CompressionCodec.NoCompressionCodec// && (compressedTopics.isEmpty() || compressedTopics.contains(topic))) { return new ByteBufferMessageSet(codec, messages.toArray(new Message[messages.size()])); } return new ByteBufferMessageSet(CompressionCodec.NoCompressionCodec, messages.toArray(new Message[messages .size()])); } public void close() { } }