/** * Copyright 2013-2014 Recruit Technologies Co., Ltd. and contributors * (see CONTRIBUTORS.md) * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. A copy of the * License is distributed with this work in the LICENSE.md file. You may * also obtain a copy of the License from * * 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.gennai.gungnir.utils.kafka; import java.util.List; import java.util.Properties; import kafka.consumer.Consumer; import kafka.consumer.ConsumerConfig; import kafka.javaapi.consumer.ConsumerConnector; import kafka.javaapi.producer.Producer; import kafka.producer.Partitioner; import kafka.producer.ProducerConfig; import kafka.serializer.Encoder; import org.I0Itec.zkclient.exception.ZkTimeoutException; import org.apache.commons.lang.StringUtils; public final class KafkaClientBuilder { public enum OffsetRequest { SMALLEST("smallest"), LARGEST("largest"); private String timeString; private OffsetRequest(String timeString) { this.timeString = timeString; } } public enum ProducerType { SYNC, ASYNC } public interface BrokersDeclarer { ProducerBuildDeclarer brokers(List<String> brokers); } public interface ProducerBuildDeclarer { ProducerBuildDeclarer requiredAcks(int requiredAcks); ProducerBuildDeclarer keySerializer(Class<? extends Encoder<?>> keySerClass); ProducerBuildDeclarer partitioner(Class<? extends Partitioner> partitionerClass); ProducerBuildDeclarer producerType(ProducerType producerType); <K> Producer<K, byte[]> build(); } public static class KafkaProducerBuilder implements BrokersDeclarer, ProducerBuildDeclarer { private List<String> brokers; private int requiredAcks; private Class<? extends Encoder<?>> keySerClass; private Class<? extends Partitioner> partitionerClass; private ProducerType producerType; @Override public ProducerBuildDeclarer brokers(List<String> brokers) { this.brokers = brokers; return this; } @Override public ProducerBuildDeclarer requiredAcks(int requiredAcks) { this.requiredAcks = requiredAcks; return this; } @Override public ProducerBuildDeclarer keySerializer(Class<? extends Encoder<?>> keySerClass) { this.keySerClass = keySerClass; return this; } @Override public ProducerBuildDeclarer partitioner(Class<? extends Partitioner> partitionerClass) { this.partitionerClass = partitionerClass; return this; } @Override public ProducerBuildDeclarer producerType(ProducerType producerType) { this.producerType = producerType; return this; } @Override public <K> Producer<K, byte[]> build() { Properties props = new Properties(); props.put("metadata.broker.list", StringUtils.join(brokers, ",")); if (keySerClass != null) { props.put("key.serializer.class", keySerClass.getName()); } if (partitionerClass != null) { props.put("partitioner.class", partitionerClass.getName()); } props.put("request.required.acks", String.valueOf(requiredAcks)); if (producerType != null) { props.put("producer.type", producerType.toString().toLowerCase()); } ProducerConfig producerConfig = new ProducerConfig(props); return new Producer<K, byte[]>(producerConfig); } } public interface GroupIdDeclarer { OffsetRequestDeclarer groupId(String groupId); } public interface OffsetRequestDeclarer { ZkServersDeclarer offset(OffsetRequest offsetRequest); } public interface ZkServersDeclarer { OptionalDeclarer zkServers(List<String> zkServers); } public interface ConsumerBuildDeclarer { ConsumerConnector build() throws InvalidConfigException; } public interface OptionalDeclarer extends ConsumerBuildDeclarer { OptionalDeclarer autoCommitInterval(Integer autoCommitInterval); OptionalDeclarer zkSessionTimeout(Integer zkSessionTimeout); OptionalDeclarer zkConnectionTimeout(Integer zkConnectionTimeout); OptionalDeclarer zkSyncTimeout(Integer zkSyncTimeout); } public static class KafkaConsumerBuilder implements GroupIdDeclarer, OffsetRequestDeclarer, ZkServersDeclarer, OptionalDeclarer { private String groupId; private OffsetRequest offsetRequest; private List<String> zkServers; private Integer autoCommitInterval; private Integer zkSessionTimeout; private Integer zkConnectionTimeout; private Integer zkSyncTimeout; @Override public OffsetRequestDeclarer groupId(String groupId) { this.groupId = groupId; return this; } @Override public ZkServersDeclarer offset(OffsetRequest offsetRequest) { this.offsetRequest = offsetRequest; return this; } @Override public OptionalDeclarer zkServers(List<String> zkServers) { this.zkServers = zkServers; return this; } @Override public OptionalDeclarer autoCommitInterval(Integer autoCommitInterval) { this.autoCommitInterval = autoCommitInterval; return this; } @Override public OptionalDeclarer zkSessionTimeout(Integer zkSessionTimeout) { this.zkSessionTimeout = zkSessionTimeout; return this; } @Override public OptionalDeclarer zkConnectionTimeout(Integer zkConnectionTimeout) { this.zkConnectionTimeout = zkConnectionTimeout; return this; } @Override public OptionalDeclarer zkSyncTimeout(Integer zkSyncTimeout) { this.zkSyncTimeout = zkSyncTimeout; return this; } @Override public ConsumerConnector build() throws InvalidConfigException { Properties props = new Properties(); props.put("group.id", groupId); props.put("auto.offset.reset", offsetRequest.timeString); props.put("zookeeper.connect", StringUtils.join(zkServers, ",")); if (autoCommitInterval != null) { props.put("auto.commit.interval.ms", String.valueOf(autoCommitInterval)); } if (zkConnectionTimeout != null) { props.put("zookeeper.connection.timeout.ms", String.valueOf(zkConnectionTimeout)); } if (zkSessionTimeout != null) { props.put("zookeeper.session.timeout.ms", String.valueOf(zkSessionTimeout)); } if (zkSyncTimeout != null) { props.put("zookeeper.sync.time.ms", String.valueOf(zkSyncTimeout)); } ConsumerConfig consumerConfig = new ConsumerConfig(props); try { return Consumer.createJavaConsumerConnector(consumerConfig); } catch (ZkTimeoutException e) { throw new InvalidConfigException(e); } } } private KafkaClientBuilder() { } public static BrokersDeclarer createProducer() { return new KafkaProducerBuilder(); } public static GroupIdDeclarer createConsumer() { return new KafkaConsumerBuilder(); } }