package com.leansoft.luxun.producer; import java.io.Closeable; import java.io.IOException; import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.leansoft.luxun.broker.Broker; import com.leansoft.luxun.common.annotations.ClientSide; import com.leansoft.luxun.common.exception.InvalidConfigException; import com.leansoft.luxun.common.exception.UnavailableProducerException; import com.leansoft.luxun.message.Message; import com.leansoft.luxun.message.MessageList; import com.leansoft.luxun.message.generated.CompressionCodec; import com.leansoft.luxun.producer.async.AsyncProducer; import com.leansoft.luxun.producer.async.AsyncProducerConfig; import com.leansoft.luxun.producer.async.CallbackHandler; import com.leansoft.luxun.producer.async.DefaultEventHandler; import com.leansoft.luxun.producer.async.EventHandler; import com.leansoft.luxun.serializer.Encoder; import com.leansoft.luxun.utils.Utils; /** * * @author bulldog * * @param <V> */ @ClientSide public class ProducerPool<V> implements Closeable { private final ProducerConfig config; private final Encoder<V> serializer; private final ConcurrentMap<Integer, SyncProducer> syncProducers; private final ConcurrentMap<Integer, AsyncProducer<V>> asyncProducers; private final EventHandler<V> eventHandler; private final CallbackHandler<V> callbackHandler; private boolean sync = true; private final Set<String> compressedTopics; private final Logger logger = LoggerFactory.getLogger(ProducerPool.class); public ProducerPool(ProducerConfig config,// Encoder<V> serializer, // ConcurrentMap<Integer, SyncProducer> syncProducers,// ConcurrentMap<Integer, AsyncProducer<V>> asyncProducers, // EventHandler<V> inputEventHandler, // CallbackHandler<V> callbackHandler) { super(); this.config = config; this.serializer = serializer; this.syncProducers = syncProducers; this.asyncProducers = asyncProducers; this.eventHandler = inputEventHandler != null ? inputEventHandler : new DefaultEventHandler<V>(config, callbackHandler); this.callbackHandler = callbackHandler; if (serializer == null) { throw new InvalidConfigException("serializer passed in is null!"); } this.sync = !"async".equalsIgnoreCase(config.getProducerType()); this.compressedTopics = new HashSet<String>(config.getCompressedTopics()); } public ProducerPool(ProducerConfig config, Encoder<V> serializer,// EventHandler<V> eventHandler,// CallbackHandler<V> callbackHandler) { this(config,// serializer,// new ConcurrentHashMap<Integer, SyncProducer>(),// new ConcurrentHashMap<Integer, AsyncProducer<V>>(),// eventHandler,// callbackHandler); } @SuppressWarnings("unchecked") public ProducerPool(ProducerConfig config, Encoder<V> serializer) { this(config,// serializer,// new ConcurrentHashMap<Integer, SyncProducer>(),// new ConcurrentHashMap<Integer, AsyncProducer<V>>(),// (EventHandler<V>) Utils.getObject(config.getEventHandler()),// (CallbackHandler<V>) Utils.getObject(config.getCbkHandler())); } /** * add a new producer, either synchronous or asynchronous, connecting * to the specified broker * * @param broker broker to producer */ public void addProducerForBroker(Broker broker) { Properties props = new Properties(); props.put("host", broker.host); props.put("port", "" + broker.port); props.putAll(config.getProperties()); if (sync) { SyncProducer producer = new SyncProducer(new SyncProducerConfig(props)); logger.info("Creating sync producer for broker id = " + broker.id + " at " + broker.host + ":" + broker.port); syncProducers.put(broker.id, producer); } else { AsyncProducer<V> producer = new AsyncProducer<V>(new AsyncProducerConfig(props),// new SyncProducer(new SyncProducerConfig(props)),// serializer,// eventHandler,// config.getEventHandlerProperties(),// this.callbackHandler, // config.getCbkHandlerProperties()); producer.start(); logger.info("Creating async producer for broker id = " + broker.id + " at " + broker.host + ":" + broker.port); asyncProducers.put(broker.id, producer); } } /** * selects either a synchronous or an asynchronous producer, for the * specified broker id and calls the send API on the selected producer * to publish the data to the specified broker * * @param ppd the producer pool request object */ public void send(ProducerPoolData<V> ppd) { if (logger.isDebugEnabled()) { logger.debug("send message: " + ppd); } if (sync) { MessageList messageList = convert(ppd); SyncProducer producer = syncProducers.get(ppd.broker.id); if (producer == null) { throw new UnavailableProducerException("Producer pool has not been initialized correctly. " + "Sync Producer for broker " + ppd.broker + " does not exist in the pool"); } producer.send(ppd.topic, messageList); } else { AsyncProducer<V> asyncProducer = asyncProducers.get(ppd.broker.id); if (asyncProducer == null) { throw new UnavailableProducerException("Producer pool has not been initialized correctly. " + "Async Producer for broker " + ppd.broker + " does not exist in the pool"); } for(V v : ppd.data) { asyncProducer.send(ppd.topic, v); } } } public void send(List<ProducerPoolData<V>> poolData) { for(ProducerPoolData<V> ppd : poolData) { send(ppd); } } // Convert to Luxun message list format private MessageList convert(ProducerPoolData<V> ppd) { CompressionCodec codec = config.getCompressionCodec(); if (codec != CompressionCodec.NO_COMPRESSION && !compressedTopics.isEmpty() && !compressedTopics.contains(ppd.topic)) { codec = CompressionCodec.NO_COMPRESSION; } MessageList messageList = new MessageList(codec); for(V v : ppd.data) { Message message = serializer.toMessage(v); messageList.add(message); } return messageList; } /** * Closes all the producers in the pool */ @Override public void close() throws IOException { logger.info("Closing all producers"); if (sync) { for (SyncProducer p : syncProducers.values()) { p.close(); } } else { for (AsyncProducer<V> p : asyncProducers.values()) { p.close(); } } } /** * This constructs and returns the value object for the producer pool * * @param topic the topic to which the data should be published * @param broker the broker * @param data the data to be published */ public ProducerPoolData<V> buildProducerPoolData(String topic, Broker broker, List<V> data) { return new ProducerPoolData<V>(topic, broker, data); } }