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

org.apache.pulsar.client.impl.ProducerBuilderImpl Maven / Gradle / Ivy

There is a newer version: 4.0.0-preview.1
Show newest version
/*
 * 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 org.apache.pulsar.client.impl;

import static org.apache.pulsar.shade.com.google.common.base.Preconditions.checkArgument;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import org.apache.pulsar.shade.org.apache.commons.lang3.StringUtils;
import org.apache.pulsar.client.api.BatcherBuilder;
import org.apache.pulsar.client.api.CompressionType;
import org.apache.pulsar.client.api.CryptoKeyReader;
import org.apache.pulsar.client.api.HashingScheme;
import org.apache.pulsar.client.api.MessageCrypto;
import org.apache.pulsar.client.api.MessageRouter;
import org.apache.pulsar.client.api.MessageRoutingMode;
import org.apache.pulsar.client.api.Producer;
import org.apache.pulsar.client.api.ProducerAccessMode;
import org.apache.pulsar.client.api.ProducerBuilder;
import org.apache.pulsar.client.api.ProducerCryptoFailureAction;
import org.apache.pulsar.client.api.PulsarClientException;
import org.apache.pulsar.client.api.Schema;
import org.apache.pulsar.client.api.interceptor.ProducerInterceptor;
import org.apache.pulsar.client.api.interceptor.ProducerInterceptorWrapper;
import org.apache.pulsar.client.impl.conf.ConfigurationDataUtils;
import org.apache.pulsar.client.impl.conf.ProducerConfigurationData;
import org.apache.pulsar.common.util.FutureUtil;

@Getter(AccessLevel.PUBLIC)
public class ProducerBuilderImpl implements ProducerBuilder {

    private final PulsarClientImpl client;
    private ProducerConfigurationData conf;
    private Schema schema;
    private List interceptorList;

    public ProducerBuilderImpl(PulsarClientImpl client, Schema schema) {
        this(client, new ProducerConfigurationData(), schema);
    }

    private ProducerBuilderImpl(PulsarClientImpl client, ProducerConfigurationData conf, Schema schema) {
        this.client = client;
        this.conf = conf;
        this.schema = schema;
    }

    /**
     * Allow to override schema in builder implementation.
     * @return
     */
    public ProducerBuilder schema(Schema schema) {
        this.schema = schema;
        return this;
    }

    @Override
    public ProducerBuilder clone() {
        return new ProducerBuilderImpl<>(client, conf.clone(), schema);
    }

    @Override
    public Producer create() throws PulsarClientException {
        try {
            return createAsync().get();
        } catch (Exception e) {
            throw PulsarClientException.unwrap(e);
        }
    }

    @Override
    public CompletableFuture> createAsync() {
        // config validation
        checkArgument(!(conf.isBatchingEnabled() && conf.isChunkingEnabled()),
                "Batching and chunking of messages can't be enabled together");
        if (conf.getTopicName() == null) {
            return FutureUtil
                    .failedFuture(new IllegalArgumentException("Topic name must be set on the producer builder"));
        }

        try {
            setMessageRoutingMode();
        } catch (PulsarClientException pce) {
            return FutureUtil.failedFuture(pce);
        }

        return interceptorList == null || interceptorList.size() == 0
                ? client.createProducerAsync(conf, schema, null)
                : client.createProducerAsync(conf, schema, new ProducerInterceptors(interceptorList));
    }

    @Override
    public ProducerBuilder loadConf(Map config) {
        conf = ConfigurationDataUtils.loadData(
            config, conf, ProducerConfigurationData.class);
        return this;
    }

    @Override
    public ProducerBuilder topic(String topicName) {
        checkArgument(StringUtils.isNotBlank(topicName), "topicName cannot be blank");
        conf.setTopicName(StringUtils.trim(topicName));
        return this;
    }

    @Override
    public ProducerBuilder producerName(String producerName) {
        conf.setProducerName(producerName);
        return this;
    }

    @Override
    public ProducerBuilder sendTimeout(int sendTimeout, @NonNull TimeUnit unit) {
        conf.setSendTimeoutMs(sendTimeout, unit);
        return this;
    }

    @Override
    public ProducerBuilder maxPendingMessages(int maxPendingMessages) {
        conf.setMaxPendingMessages(maxPendingMessages);
        return this;
    }

    @Deprecated
    @Override
    public ProducerBuilder maxPendingMessagesAcrossPartitions(int maxPendingMessagesAcrossPartitions) {
        conf.setMaxPendingMessagesAcrossPartitions(maxPendingMessagesAcrossPartitions);
        return this;
    }

    @Override
    public ProducerBuilder accessMode(ProducerAccessMode accessMode) {
        conf.setAccessMode(accessMode);
        return this;
    }

    @Override
    public ProducerBuilder blockIfQueueFull(boolean blockIfQueueFull) {
        conf.setBlockIfQueueFull(blockIfQueueFull);
        return this;
    }

    @Override
    public ProducerBuilder messageRoutingMode(@NonNull MessageRoutingMode messageRouteMode) {
        conf.setMessageRoutingMode(messageRouteMode);
        return this;
    }

    @Override
    public ProducerBuilder compressionType(@NonNull CompressionType compressionType) {
        conf.setCompressionType(compressionType);
        return this;
    }

    @Override
    public ProducerBuilder hashingScheme(@NonNull HashingScheme hashingScheme) {
        conf.setHashingScheme(hashingScheme);
        return this;
    }

    @Override
    public ProducerBuilder messageRouter(@NonNull MessageRouter messageRouter) {
        conf.setCustomMessageRouter(messageRouter);
        return this;
    }

    @Override
    public ProducerBuilder enableBatching(boolean batchMessagesEnabled) {
        conf.setBatchingEnabled(batchMessagesEnabled);
        return this;
    }

    @Override
    public ProducerBuilder enableChunking(boolean chunkingEnabled) {
        conf.setChunkingEnabled(chunkingEnabled);
        return this;
    }

    @Override
    public ProducerBuilder chunkMaxMessageSize(int chunkMaxMessageSize) {
        conf.setChunkMaxMessageSize(chunkMaxMessageSize);
        return this;
    }

    @Override
    public ProducerBuilder cryptoKeyReader(@NonNull CryptoKeyReader cryptoKeyReader) {
        conf.setCryptoKeyReader(cryptoKeyReader);
        return this;
    }

    @Override
    public ProducerBuilder defaultCryptoKeyReader(String publicKey) {
        checkArgument(StringUtils.isNotBlank(publicKey), "publicKey cannot be blank");
        return cryptoKeyReader(DefaultCryptoKeyReader.builder().defaultPublicKey(publicKey).build());
    }

    @Override
    public ProducerBuilder defaultCryptoKeyReader(@NonNull Map publicKeys) {
        checkArgument(!publicKeys.isEmpty(), "publicKeys cannot be empty");
        return cryptoKeyReader(DefaultCryptoKeyReader.builder().publicKeys(publicKeys).build());
    }

    @Override
    public ProducerBuilder messageCrypto(MessageCrypto messageCrypto) {
        conf.setMessageCrypto(messageCrypto);
        return this;
    }

    @Override
    public ProducerBuilder addEncryptionKey(String key) {
        checkArgument(StringUtils.isNotBlank(key), "Encryption key cannot be blank");
        conf.getEncryptionKeys().add(key);
        return this;
    }

    @Override
    public ProducerBuilder cryptoFailureAction(@NonNull ProducerCryptoFailureAction action) {
        conf.setCryptoFailureAction(action);
        return this;
    }

    @Override
    public ProducerBuilder batchingMaxPublishDelay(long batchDelay, @NonNull TimeUnit timeUnit) {
        conf.setBatchingMaxPublishDelayMicros(batchDelay, timeUnit);
        return this;
    }

    @Override
    public ProducerBuilder roundRobinRouterBatchingPartitionSwitchFrequency(int frequency) {
        conf.setBatchingPartitionSwitchFrequencyByPublishDelay(frequency);
        return this;
    }

    @Override
    public ProducerBuilder batchingMaxMessages(int batchMessagesMaxMessagesPerBatch) {
        conf.setBatchingMaxMessages(batchMessagesMaxMessagesPerBatch);
        return this;
    }

    @Override
    public ProducerBuilder batchingMaxBytes(int batchingMaxBytes) {
        conf.setBatchingMaxBytes(batchingMaxBytes);
        return this;
    }

    @Override
    public ProducerBuilder batcherBuilder(BatcherBuilder batcherBuilder) {
        conf.setBatcherBuilder(batcherBuilder);
        return this;
    }


    @Override
    public ProducerBuilder initialSequenceId(long initialSequenceId) {
        conf.setInitialSequenceId(initialSequenceId);
        return this;
    }

    @Override
    public ProducerBuilder property(String key, String value) {
        checkArgument(StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value),
                "property key/value cannot be blank");
        conf.getProperties().put(key, value);
        return this;
    }

    @Override
    public ProducerBuilder properties(@NonNull Map properties) {
        properties.entrySet().forEach(entry ->
            checkArgument(StringUtils.isNotBlank(entry.getKey()) && StringUtils.isNotBlank(entry.getValue()),
                    "properties' key/value cannot be blank"));
        conf.getProperties().putAll(properties);
        return this;
    }

    @Override
    public ProducerBuilder intercept(ProducerInterceptor... interceptors) {
        if (interceptorList == null) {
            interceptorList = new ArrayList<>();
        }
        interceptorList.addAll(Arrays.asList(interceptors));
        return this;
    }

    @Override
    @Deprecated
    public ProducerBuilder intercept(org.apache.pulsar.client.api.ProducerInterceptor... interceptors) {
        if (interceptorList == null) {
            interceptorList = new ArrayList<>();
        }
        interceptorList.addAll(Arrays.stream(interceptors).map(ProducerInterceptorWrapper::new)
                                     .collect(Collectors.toList()));
        return this;
    }
    @Override
    public ProducerBuilder autoUpdatePartitions(boolean autoUpdate) {
        conf.setAutoUpdatePartitions(autoUpdate);
        return this;
    }

    @Override
    public ProducerBuilder autoUpdatePartitionsInterval(int interval, TimeUnit unit) {
        conf.setAutoUpdatePartitionsIntervalSeconds(interval, unit);
        return this;
    }

    @Override
    public ProducerBuilder enableMultiSchema(boolean multiSchema) {
        conf.setMultiSchema(multiSchema);
        return this;
    }

    @Override
    public ProducerBuilder enableLazyStartPartitionedProducers(boolean lazyStartPartitionedProducers) {
        conf.setLazyStartPartitionedProducers(lazyStartPartitionedProducers);
        return this;
    }

    /**
     * Use this config to automatically create an initial subscription when creating the topic.
     * If this field is not set, the initial subscription will not be created.
     * If this field is set but the broker's `allowAutoSubscriptionCreation` is disabled, the producer will fail to
     * be created.
     * This method is limited to internal use. This method will only be used when the consumer creates the dlq producer.
     *
     * @param initialSubscriptionName Name of the initial subscription of the topic.
     * @return the producer builder implementation instance
     */
    public ProducerBuilderImpl initialSubscriptionName(String initialSubscriptionName) {
        conf.setInitialSubscriptionName(initialSubscriptionName);
        return this;
    }

    private void setMessageRoutingMode() throws PulsarClientException {
        if (conf.getMessageRoutingMode() == null && conf.getCustomMessageRouter() == null) {
            messageRoutingMode(MessageRoutingMode.RoundRobinPartition);
        } else if (conf.getMessageRoutingMode() == null && conf.getCustomMessageRouter() != null) {
            messageRoutingMode(MessageRoutingMode.CustomPartition);
        } else if (conf.getMessageRoutingMode() == MessageRoutingMode.CustomPartition
                && conf.getCustomMessageRouter() == null) {
            throw new PulsarClientException("When 'messageRoutingMode' is " + MessageRoutingMode.CustomPartition
                + ", 'messageRouter' should be set");
        } else if (conf.getMessageRoutingMode() != MessageRoutingMode.CustomPartition
                && conf.getCustomMessageRouter() != null) {
            throw new PulsarClientException("When 'messageRouter' is set, 'messageRoutingMode' "
                    + "should be set as " + MessageRoutingMode.CustomPartition);
        }
    }

    @Override
    public String toString() {
        return conf != null ? conf.toString() : "";
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy