pulsarSources) {
- return new PulsarFunctionAdministration(pulsarAdministration, pulsarFunctions, pulsarSinks, pulsarSources,
- this.properties.getFunction().getFailFast(), this.properties.getFunction().getPropagateFailures(),
- this.properties.getFunction().getPropagateStopFailures());
- }
-
- @Bean
- @ConditionalOnMissingBean
- public PulsarReaderFactory> pulsarReaderFactory(PulsarClient pulsarClient) {
- return new DefaultPulsarReaderFactory<>(pulsarClient, this.properties.buildReaderProperties());
- }
-
-}
diff --git a/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/PulsarProperties.java b/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/PulsarProperties.java
deleted file mode 100644
index 914a8a61..00000000
--- a/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/PulsarProperties.java
+++ /dev/null
@@ -1,1390 +0,0 @@
-/*
- * Copyright 2022-2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.autoconfigure;
-
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-
-import org.apache.pulsar.client.api.ProxyProtocol;
-import org.apache.pulsar.common.schema.SchemaType;
-
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.boot.context.properties.NestedConfigurationProperty;
-import org.springframework.boot.context.properties.PropertyMapper;
-import org.springframework.lang.Nullable;
-import org.springframework.pulsar.listener.AckMode;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
-import org.springframework.util.unit.DataSize;
-
-/**
- * Configuration properties for Spring for Apache Pulsar.
- *
- * Users should refer to Pulsar documentation for complete descriptions of these
- * properties.
- *
- * @author Soby Chacko
- * @author Alexander Preuß
- * @author Christophe Bornet
- * @author Chris Bono
- */
-@ConfigurationProperties(prefix = "spring.pulsar")
-public class PulsarProperties {
-
- @NestedConfigurationProperty
- private final ConsumerConfigProperties consumer = new ConsumerConfigProperties();
-
- private final Client client = new Client();
-
- private final Function function = new Function();
-
- private final Listener listener = new Listener();
-
- @NestedConfigurationProperty
- private final ProducerConfigProperties producer = new ProducerConfigProperties();
-
- private final Template template = new Template();
-
- private final Admin admin = new Admin();
-
- private final Reader reader = new Reader();
-
- private final Defaults defaults = new Defaults();
-
- public ConsumerConfigProperties getConsumer() {
- return this.consumer;
- }
-
- public Client getClient() {
- return this.client;
- }
-
- public Listener getListener() {
- return this.listener;
- }
-
- public Function getFunction() {
- return this.function;
- }
-
- public ProducerConfigProperties getProducer() {
- return this.producer;
- }
-
- public Template getTemplate() {
- return this.template;
- }
-
- public Admin getAdministration() {
- return this.admin;
- }
-
- public Reader getReader() {
- return this.reader;
- }
-
- public Defaults getDefaults() {
- return this.defaults;
- }
-
- public Map buildConsumerProperties() {
- return new HashMap<>(this.consumer.buildProperties());
- }
-
- public Map buildClientProperties() {
- return new HashMap<>(this.client.buildProperties());
- }
-
- public Map buildProducerProperties() {
- return new HashMap<>(this.producer.buildProperties());
- }
-
- public Map buildAdminProperties() {
- return new HashMap<>(this.admin.buildProperties());
- }
-
- public Map buildReaderProperties() {
- return new HashMap<>(this.reader.buildProperties());
- }
-
- public static class Template {
-
- /**
- * Whether to record observations for send operations when the Observations API is
- * available.
- */
- private Boolean observationsEnabled = true;
-
- public Boolean isObservationsEnabled() {
- return this.observationsEnabled;
- }
-
- public void setObservationsEnabled(Boolean observationsEnabled) {
- this.observationsEnabled = observationsEnabled;
- }
-
- }
-
- public static class Cache {
-
- /** Time period to expire unused entries in the cache. */
- private Duration expireAfterAccess = Duration.ofMinutes(1);
-
- /** Maximum size of cache (entries). */
- private Long maximumSize = 1000L;
-
- /** Initial size of cache. */
- private Integer initialCapacity = 50;
-
- public Duration getExpireAfterAccess() {
- return this.expireAfterAccess;
- }
-
- public void setExpireAfterAccess(Duration expireAfterAccess) {
- this.expireAfterAccess = expireAfterAccess;
- }
-
- public Long getMaximumSize() {
- return this.maximumSize;
- }
-
- public void setMaximumSize(Long maximumSize) {
- this.maximumSize = maximumSize;
- }
-
- public Integer getInitialCapacity() {
- return this.initialCapacity;
- }
-
- public void setInitialCapacity(Integer initialCapacity) {
- this.initialCapacity = initialCapacity;
- }
-
- }
-
- public static class Client {
-
- /**
- * Pulsar service URL in the format
- * '(pulsar|pulsar+ssl)://<host>:<port>'.
- */
- private String serviceUrl = "pulsar://localhost:6650";
-
- /**
- * Listener name for lookup. Clients can use listenerName to choose one of the
- * listeners as the service URL to create a connection to the broker. To use this,
- * "advertisedListeners" must be enabled on the broker.
- */
- private String listenerName;
-
- /**
- * Fully qualified class name of the authentication plugin.
- */
- private String authPluginClassName;
-
- /**
- * Authentication parameter(s) as a JSON encoded string.
- */
- private String authParams;
-
- /**
- * Authentication parameter(s) as a map of parameter names to parameter values.
- */
- private Map authentication;
-
- /**
- * Client operation timeout.
- */
- private Duration operationTimeout = Duration.ofSeconds(30);
-
- /**
- * Client lookup timeout.
- */
- private Duration lookupTimeout = Duration.ofMillis(-1);
-
- /**
- * Number of threads to be used for handling connections to brokers.
- */
- private Integer numIoThreads = 1;
-
- /**
- * Number of threads to be used for message listeners. The listener thread pool is
- * shared across all the consumers and readers that are using a "listener" model
- * to get messages. For a given consumer, the listener will always be invoked from
- * the same thread, to ensure ordering.
- */
- private Integer numListenerThreads = 1;
-
- /**
- * Maximum number of connections that the client will open to a single broker.
- */
- private Integer numConnectionsPerBroker = 1;
-
- /**
- * Whether to use TCP no-delay flag on the connection, to disable Nagle algorithm.
- */
- private Boolean useTcpNoDelay = true;
-
- /**
- * Whether to use TLS encryption on the connection.
- */
- private Boolean useTls = false;
-
- /**
- * Whether the hostname is validated when the proxy creates a TLS connection with
- * brokers.
- */
- private Boolean tlsHostnameVerificationEnable = false;
-
- /**
- * Path to the trusted TLS certificate file.
- */
- private String tlsTrustCertsFilePath;
-
- /**
- * Whether the client accepts untrusted TLS certificates from the broker.
- */
- private Boolean tlsAllowInsecureConnection = false;
-
- /**
- * Enable KeyStore instead of PEM type configuration if TLS is enabled.
- */
- private Boolean useKeyStoreTls = false;
-
- /**
- * Name of the security provider used for SSL connections.
- */
- private String sslProvider;
-
- /**
- * File format of the trust store file.
- */
- private String tlsTrustStoreType;
-
- /**
- * Location of the trust store file.
- */
- private String tlsTrustStorePath;
-
- /**
- * Store password for the key store file.
- */
- private String tlsTrustStorePassword;
-
- /**
- * Comma-separated list of cipher suites. This is a named combination of
- * authentication, encryption, MAC and key exchange algorithm used to negotiate
- * the security settings for a network connection using TLS or SSL network
- * protocol. By default, all the available cipher suites are supported.
- */
- private Set tlsCiphers;
-
- /**
- * Comma-separated list of SSL protocols used to generate the SSLContext. Allowed
- * values in recent JVMs are TLS, TLSv1.3, TLSv1.2 and TLSv1.1.
- */
- private Set tlsProtocols;
-
- /**
- * Interval between each stat info.
- */
- private Duration statsInterval = Duration.ofSeconds(60);
-
- /**
- * Number of concurrent lookup-requests allowed to send on each broker-connection
- * to prevent overload on broker.
- */
- private Integer maxConcurrentLookupRequest = 5000;
-
- /**
- * Number of max lookup-requests allowed on each broker-connection to prevent
- * overload on broker.
- */
- private Integer maxLookupRequest = 50000;
-
- /**
- * Maximum number of times a lookup-request to a broker will be redirected.
- */
- private Integer maxLookupRedirects = 20;
-
- /**
- * Maximum number of broker-rejected requests in a certain timeframe, after which
- * the current connection is closed and a new connection is created by the client.
- */
- private Integer maxNumberOfRejectedRequestPerConnection = 50;
-
- /**
- * Keep alive interval for broker-client connection.
- */
- private Duration keepAliveInterval = Duration.ofSeconds(30);
-
- /**
- * Duration to wait for a connection to a broker to be established.
- */
- private Duration connectionTimeout = Duration.ofSeconds(10);
-
- /**
- * Maximum duration for completing a request.
- */
- private Duration requestTimeout = Duration.ofMinutes(1);
-
- /**
- * Initial backoff interval.
- */
- private Duration initialBackoffInterval = Duration.ofMillis(100);
-
- /**
- * Maximum backoff interval.
- */
- private Duration maxBackoffInterval = Duration.ofSeconds(30);
-
- /**
- * Enables spin-waiting on executors and IO threads in order to reduce latency
- * during context switches.
- */
- private Boolean enableBusyWait = false;
-
- /**
- * Limit of direct memory that will be allocated by the client.
- */
- private DataSize memoryLimit = DataSize.ofMegabytes(64);
-
- /**
- * URL of proxy service. proxyServiceUrl and proxyProtocol must be mutually
- * inclusive.
- */
- private String proxyServiceUrl;
-
- /**
- * Protocol of proxy service. proxyServiceUrl and proxyProtocol must be mutually
- * inclusive.
- */
- private ProxyProtocol proxyProtocol;
-
- /**
- * Enables transactions. To use this, start the transactionCoordinatorClient with
- * the pulsar client.
- */
- private Boolean enableTransaction = false;
-
- /**
- * DNS lookup bind address.
- */
- private String dnsLookupBindAddress;
-
- /**
- * DNS lookup bind port.
- */
- private Integer dnsLookupBindPort = 0;
-
- /**
- * SOCKS5 proxy address.
- */
- private String socks5ProxyAddress;
-
- /**
- * SOCKS5 proxy username.
- */
- private String socks5ProxyUsername;
-
- /**
- * SOCKS5 proxy password.
- */
- private String socks5ProxyPassword;
-
- public String getServiceUrl() {
- return this.serviceUrl;
- }
-
- public void setServiceUrl(String serviceUrl) {
- this.serviceUrl = serviceUrl;
- }
-
- public String getListenerName() {
- return this.listenerName;
- }
-
- public void setListenerName(String listenerName) {
- this.listenerName = listenerName;
- }
-
- public String getAuthPluginClassName() {
- return this.authPluginClassName;
- }
-
- public void setAuthPluginClassName(String authPluginClassName) {
- this.authPluginClassName = authPluginClassName;
- }
-
- public String getAuthParams() {
- return this.authParams;
- }
-
- public void setAuthParams(String authParams) {
- this.authParams = authParams;
- }
-
- public Map getAuthentication() {
- return this.authentication;
- }
-
- public void setAuthentication(Map authentication) {
- this.authentication = authentication;
- }
-
- public Duration getOperationTimeout() {
- return this.operationTimeout;
- }
-
- public void setOperationTimeout(Duration operationTimeout) {
- this.operationTimeout = operationTimeout;
- }
-
- public Duration getLookupTimeout() {
- return this.lookupTimeout;
- }
-
- public void setLookupTimeout(Duration lookupTimeout) {
- this.lookupTimeout = lookupTimeout;
- }
-
- public Integer getNumIoThreads() {
- return this.numIoThreads;
- }
-
- public void setNumIoThreads(Integer numIoThreads) {
- this.numIoThreads = numIoThreads;
- }
-
- public Integer getNumListenerThreads() {
- return this.numListenerThreads;
- }
-
- public void setNumListenerThreads(Integer numListenerThreads) {
- this.numListenerThreads = numListenerThreads;
- }
-
- public Integer getNumConnectionsPerBroker() {
- return this.numConnectionsPerBroker;
- }
-
- public void setNumConnectionsPerBroker(Integer numConnectionsPerBroker) {
- this.numConnectionsPerBroker = numConnectionsPerBroker;
- }
-
- public Boolean getUseTcpNoDelay() {
- return this.useTcpNoDelay;
- }
-
- public void setUseTcpNoDelay(Boolean useTcpNoDelay) {
- this.useTcpNoDelay = useTcpNoDelay;
- }
-
- public Boolean getUseTls() {
- return this.useTls;
- }
-
- public void setUseTls(Boolean useTls) {
- this.useTls = useTls;
- }
-
- public Boolean getTlsHostnameVerificationEnable() {
- return this.tlsHostnameVerificationEnable;
- }
-
- public void setTlsHostnameVerificationEnable(Boolean tlsHostnameVerificationEnable) {
- this.tlsHostnameVerificationEnable = tlsHostnameVerificationEnable;
- }
-
- public String getTlsTrustCertsFilePath() {
- return this.tlsTrustCertsFilePath;
- }
-
- public void setTlsTrustCertsFilePath(String tlsTrustCertsFilePath) {
- this.tlsTrustCertsFilePath = tlsTrustCertsFilePath;
- }
-
- public Boolean getTlsAllowInsecureConnection() {
- return this.tlsAllowInsecureConnection;
- }
-
- public void setTlsAllowInsecureConnection(Boolean tlsAllowInsecureConnection) {
- this.tlsAllowInsecureConnection = tlsAllowInsecureConnection;
- }
-
- public Boolean getUseKeyStoreTls() {
- return this.useKeyStoreTls;
- }
-
- public void setUseKeyStoreTls(Boolean useKeyStoreTls) {
- this.useKeyStoreTls = useKeyStoreTls;
- }
-
- public String getSslProvider() {
- return this.sslProvider;
- }
-
- public void setSslProvider(String sslProvider) {
- this.sslProvider = sslProvider;
- }
-
- public String getTlsTrustStoreType() {
- return this.tlsTrustStoreType;
- }
-
- public void setTlsTrustStoreType(String tlsTrustStoreType) {
- this.tlsTrustStoreType = tlsTrustStoreType;
- }
-
- public String getTlsTrustStorePath() {
- return this.tlsTrustStorePath;
- }
-
- public void setTlsTrustStorePath(String tlsTrustStorePath) {
- this.tlsTrustStorePath = tlsTrustStorePath;
- }
-
- public String getTlsTrustStorePassword() {
- return this.tlsTrustStorePassword;
- }
-
- public void setTlsTrustStorePassword(String tlsTrustStorePassword) {
- this.tlsTrustStorePassword = tlsTrustStorePassword;
- }
-
- public Set getTlsCiphers() {
- return this.tlsCiphers;
- }
-
- public void setTlsCiphers(Set tlsCiphers) {
- this.tlsCiphers = tlsCiphers;
- }
-
- public Set getTlsProtocols() {
- return this.tlsProtocols;
- }
-
- public void setTlsProtocols(Set tlsProtocols) {
- this.tlsProtocols = tlsProtocols;
- }
-
- public Duration getStatsInterval() {
- return this.statsInterval;
- }
-
- public void setStatsInterval(Duration statsInterval) {
- this.statsInterval = statsInterval;
- }
-
- public Integer getMaxConcurrentLookupRequest() {
- return this.maxConcurrentLookupRequest;
- }
-
- public void setMaxConcurrentLookupRequest(Integer maxConcurrentLookupRequest) {
- this.maxConcurrentLookupRequest = maxConcurrentLookupRequest;
- }
-
- public Integer getMaxLookupRequest() {
- return this.maxLookupRequest;
- }
-
- public void setMaxLookupRequest(Integer maxLookupRequest) {
- this.maxLookupRequest = maxLookupRequest;
- }
-
- public Integer getMaxLookupRedirects() {
- return this.maxLookupRedirects;
- }
-
- public void setMaxLookupRedirects(Integer maxLookupRedirects) {
- this.maxLookupRedirects = maxLookupRedirects;
- }
-
- public Integer getMaxNumberOfRejectedRequestPerConnection() {
- return this.maxNumberOfRejectedRequestPerConnection;
- }
-
- public void setMaxNumberOfRejectedRequestPerConnection(Integer maxNumberOfRejectedRequestPerConnection) {
- this.maxNumberOfRejectedRequestPerConnection = maxNumberOfRejectedRequestPerConnection;
- }
-
- public Duration getKeepAliveInterval() {
- return this.keepAliveInterval;
- }
-
- public void setKeepAliveInterval(Duration keepAliveInterval) {
- this.keepAliveInterval = keepAliveInterval;
- }
-
- public Duration getConnectionTimeout() {
- return this.connectionTimeout;
- }
-
- public void setConnectionTimeout(Duration connectionTimeout) {
- this.connectionTimeout = connectionTimeout;
- }
-
- public Duration getRequestTimeout() {
- return this.requestTimeout;
- }
-
- public void setRequestTimeout(Duration requestTimeout) {
- this.requestTimeout = requestTimeout;
- }
-
- public Duration getInitialBackoffInterval() {
- return this.initialBackoffInterval;
- }
-
- public void setInitialBackoffInterval(Duration initialBackoffInterval) {
- this.initialBackoffInterval = initialBackoffInterval;
- }
-
- public Duration getMaxBackoffInterval() {
- return this.maxBackoffInterval;
- }
-
- public void setMaxBackoffInterval(Duration maxBackoffInterval) {
- this.maxBackoffInterval = maxBackoffInterval;
- }
-
- public Boolean getEnableBusyWait() {
- return this.enableBusyWait;
- }
-
- public void setEnableBusyWait(Boolean enableBusyWait) {
- this.enableBusyWait = enableBusyWait;
- }
-
- public DataSize getMemoryLimit() {
- return this.memoryLimit;
- }
-
- public void setMemoryLimit(DataSize memoryLimit) {
- this.memoryLimit = memoryLimit;
- }
-
- public String getProxyServiceUrl() {
- return this.proxyServiceUrl;
- }
-
- public void setProxyServiceUrl(String proxyServiceUrl) {
- this.proxyServiceUrl = proxyServiceUrl;
- }
-
- public ProxyProtocol getProxyProtocol() {
- return this.proxyProtocol;
- }
-
- public void setProxyProtocol(ProxyProtocol proxyProtocol) {
- this.proxyProtocol = proxyProtocol;
- }
-
- public Boolean getEnableTransaction() {
- return this.enableTransaction;
- }
-
- public void setEnableTransaction(Boolean enableTransaction) {
- this.enableTransaction = enableTransaction;
- }
-
- public String getDnsLookupBindAddress() {
- return this.dnsLookupBindAddress;
- }
-
- public void setDnsLookupBindAddress(String dnsLookupBindAddress) {
- this.dnsLookupBindAddress = dnsLookupBindAddress;
- }
-
- public Integer getDnsLookupBindPort() {
- return this.dnsLookupBindPort;
- }
-
- public void setDnsLookupBindPort(Integer dnsLookupBindPort) {
- this.dnsLookupBindPort = dnsLookupBindPort;
- }
-
- public String getSocks5ProxyAddress() {
- return this.socks5ProxyAddress;
- }
-
- public void setSocks5ProxyAddress(String socks5ProxyAddress) {
- this.socks5ProxyAddress = socks5ProxyAddress;
- }
-
- public String getSocks5ProxyUsername() {
- return this.socks5ProxyUsername;
- }
-
- public void setSocks5ProxyUsername(String socks5ProxyUsername) {
- this.socks5ProxyUsername = socks5ProxyUsername;
- }
-
- public String getSocks5ProxyPassword() {
- return this.socks5ProxyPassword;
- }
-
- public void setSocks5ProxyPassword(String socks5ProxyPassword) {
- this.socks5ProxyPassword = socks5ProxyPassword;
- }
-
- public Map buildProperties() {
- if (StringUtils.hasText(this.getAuthParams()) && !CollectionUtils.isEmpty(this.getAuthentication())) {
- throw new IllegalArgumentException(
- "Cannot set both spring.pulsar.client.authParams and spring.pulsar.client.authentication.*");
- }
-
- PulsarProperties.Properties properties = new Properties();
-
- PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
- map.from(this::getServiceUrl).to(properties.in("serviceUrl"));
- map.from(this::getListenerName).to(properties.in("listenerName"));
- map.from(this::getAuthPluginClassName).to(properties.in("authPluginClassName"));
- map.from(this::getAuthParams).to(properties.in("authParams"));
- map.from(this::getAuthentication).as(AuthParameterUtils::maybeConvertToEncodedParamString)
- .to(properties.in("authParams"));
- map.from(this::getOperationTimeout).as(Duration::toMillis).to(properties.in("operationTimeoutMs"));
- map.from(this::getLookupTimeout).as(Duration::toMillis).to(properties.in("lookupTimeoutMs"));
- map.from(this::getNumIoThreads).to(properties.in("numIoThreads"));
- map.from(this::getNumListenerThreads).to(properties.in("numListenerThreads"));
- map.from(this::getNumConnectionsPerBroker).to(properties.in("connectionsPerBroker"));
- map.from(this::getUseTcpNoDelay).to(properties.in("useTcpNoDelay"));
- map.from(this::getUseTls).to(properties.in("useTls"));
- map.from(this::getTlsHostnameVerificationEnable).to(properties.in("tlsHostnameVerificationEnable"));
- map.from(this::getTlsTrustCertsFilePath).to(properties.in("tlsTrustCertsFilePath"));
- map.from(this::getTlsAllowInsecureConnection).to(properties.in("tlsAllowInsecureConnection"));
- map.from(this::getUseKeyStoreTls).to(properties.in("useKeyStoreTls"));
- map.from(this::getSslProvider).to(properties.in("sslProvider"));
- map.from(this::getTlsTrustStoreType).to(properties.in("tlsTrustStoreType"));
- map.from(this::getTlsTrustStorePath).to(properties.in("tlsTrustStorePath"));
- map.from(this::getTlsTrustStorePassword).to(properties.in("tlsTrustStorePassword"));
- map.from(this::getTlsCiphers).to(properties.in("tlsCiphers"));
- map.from(this::getTlsProtocols).to(properties.in("tlsProtocols"));
- map.from(this::getStatsInterval).as(Duration::toSeconds).to(properties.in("statsIntervalSeconds"));
- map.from(this::getMaxConcurrentLookupRequest).to(properties.in("concurrentLookupRequest"));
- map.from(this::getMaxLookupRequest).to(properties.in("maxLookupRequest"));
- map.from(this::getMaxLookupRedirects).to(properties.in("maxLookupRedirects"));
- map.from(this::getMaxNumberOfRejectedRequestPerConnection)
- .to(properties.in("maxNumberOfRejectedRequestPerConnection"));
- map.from(this::getKeepAliveInterval).asInt(Duration::toSeconds)
- .to(properties.in("keepAliveIntervalSeconds"));
- map.from(this::getConnectionTimeout).asInt(Duration::toMillis).to(properties.in("connectionTimeoutMs"));
- map.from(this::getRequestTimeout).asInt(Duration::toMillis).to(properties.in("requestTimeoutMs"));
- map.from(this::getInitialBackoffInterval).as(Duration::toNanos)
- .to(properties.in("initialBackoffIntervalNanos"));
- map.from(this::getMaxBackoffInterval).as(Duration::toNanos).to(properties.in("maxBackoffIntervalNanos"));
- map.from(this::getEnableBusyWait).to(properties.in("enableBusyWait"));
- map.from(this::getMemoryLimit).as(DataSize::toBytes).to(properties.in("memoryLimitBytes"));
- map.from(this::getProxyServiceUrl).to(properties.in("proxyServiceUrl"));
- map.from(this::getProxyProtocol).to(properties.in("proxyProtocol"));
- map.from(this::getEnableTransaction).to(properties.in("enableTransaction"));
- map.from(this::getDnsLookupBindAddress).to(properties.in("dnsLookupBindAddress"));
- map.from(this::getDnsLookupBindPort).to(properties.in("dnsLookupBindPort"));
- map.from(this::getSocks5ProxyAddress).to(properties.in("socks5ProxyAddress"));
- map.from(this::getSocks5ProxyUsername).to(properties.in("socks5ProxyUsername"));
- map.from(this::getSocks5ProxyPassword).to(properties.in("socks5ProxyPassword"));
-
- return properties;
- }
-
- }
-
- public static class Function {
-
- /**
- * Whether to stop processing further function creates/updates when a failure
- * occurs.
- */
- private Boolean failFast = Boolean.TRUE;
-
- /**
- * Whether to throw an exception if any failure is encountered during server
- * startup while creating/updating functions.
- */
- private Boolean propagateFailures = Boolean.TRUE;
-
- /**
- * Whether to throw an exception if any failure is encountered during server
- * shutdown while enforcing stop policy on functions.
- */
- private Boolean propagateStopFailures = Boolean.FALSE;
-
- public Boolean getFailFast() {
- return this.failFast;
- }
-
- public void setFailFast(Boolean failFast) {
- this.failFast = failFast;
- }
-
- public Boolean getPropagateFailures() {
- return this.propagateFailures;
- }
-
- public void setPropagateFailures(Boolean propagateFailures) {
- this.propagateFailures = propagateFailures;
- }
-
- public Boolean getPropagateStopFailures() {
- return this.propagateStopFailures;
- }
-
- public void setPropagateStopFailures(Boolean propagateStopFailures) {
- this.propagateStopFailures = propagateStopFailures;
- }
-
- }
-
- public static class Listener {
-
- /**
- * AckMode for acknowledgements. Allowed values are RECORD, BATCH, MANUAL.
- */
- private AckMode ackMode;
-
- /**
- * SchemaType of the consumed messages.
- */
- private SchemaType schemaType;
-
- /**
- * Max number of messages in a single batch request.
- */
- private Integer maxNumMessages = -1;
-
- /**
- * Max size in a single batch request.
- */
- private DataSize maxNumBytes = DataSize.ofMegabytes(10);
-
- /**
- * Duration to wait for enough message to fill a batch request before timing out.
- */
- private Duration batchTimeout = Duration.ofMillis(100);
-
- /**
- * Whether to record observations for receive operations when the Observations API
- * is available.
- */
- private Boolean observationsEnabled = true;
-
- public AckMode getAckMode() {
- return this.ackMode;
- }
-
- public void setAckMode(AckMode ackMode) {
- this.ackMode = ackMode;
- }
-
- public SchemaType getSchemaType() {
- return this.schemaType;
- }
-
- public void setSchemaType(SchemaType schemaType) {
- this.schemaType = schemaType;
- }
-
- public Integer getMaxNumMessages() {
- return this.maxNumMessages;
- }
-
- public void setMaxNumMessages(Integer maxNumMessages) {
- this.maxNumMessages = maxNumMessages;
- }
-
- public DataSize getMaxNumBytes() {
- return this.maxNumBytes;
- }
-
- public void setMaxNumBytes(DataSize maxNumBytes) {
- this.maxNumBytes = maxNumBytes;
- }
-
- public Duration getBatchTimeout() {
- return this.batchTimeout;
- }
-
- public void setBatchTimeout(Duration batchTimeout) {
- this.batchTimeout = batchTimeout;
- }
-
- public Boolean isObservationsEnabled() {
- return this.observationsEnabled;
- }
-
- public void setObservationsEnabled(Boolean observationsEnabled) {
- this.observationsEnabled = observationsEnabled;
- }
-
- }
-
- public static class Admin {
-
- /**
- * Pulsar web URL for the admin endpoint in the format
- * '(http|https)://<host>:<port>'.
- */
- private String serviceUrl = "http://localhost:8080";
-
- /**
- * Fully qualified class name of the authentication plugin.
- */
- private String authPluginClassName;
-
- /**
- * Authentication parameter(s) as a JSON encoded string.
- */
- private String authParams;
-
- /**
- * Authentication parameter(s) as a map of parameter names to parameter values.
- */
- private Map authentication;
-
- /**
- * Path to the trusted TLS certificate file.
- */
- private String tlsTrustCertsFilePath;
-
- /**
- * Whether the client accepts untrusted TLS certificates from the broker.
- */
- private Boolean tlsAllowInsecureConnection = false;
-
- /**
- * Whether the hostname is validated when the proxy creates a TLS connection with
- * brokers.
- */
- private Boolean tlsHostnameVerificationEnable = false;
-
- /**
- * Enable KeyStore instead of PEM type configuration if TLS is enabled.
- */
- private Boolean useKeyStoreTls = false;
-
- /**
- * Name of the security provider used for SSL connections.
- */
- private String sslProvider;
-
- /**
- * File format of the trust store file.
- */
- private String tlsTrustStoreType;
-
- /**
- * Location of the trust store file.
- */
- private String tlsTrustStorePath;
-
- /**
- * Store password for the key store file.
- */
- private String tlsTrustStorePassword;
-
- /**
- * List of cipher suites. This is a named combination of authentication,
- * encryption, MAC and key exchange algorithm used to negotiate the security
- * settings for a network connection using TLS or SSL network protocol. By
- * default, all the available cipher suites are supported.
- */
- private Set tlsCiphers;
-
- /**
- * List of SSL protocols used to generate the SSLContext. Allowed values in recent
- * JVMs are TLS, TLSv1.3, TLSv1.2 and TLSv1.1.
- */
- private Set tlsProtocols;
-
- /**
- * Duration to wait for a connection to server to be established.
- */
- private Duration connectionTimeout = Duration.ofMinutes(1);
-
- /**
- * Server response read time out for any request.
- */
- private Duration readTimeout = Duration.ofMinutes(1);
-
- /**
- * Server request time out for any request.
- */
- private Duration requestTimeout = Duration.ofMinutes(5);
-
- /**
- * Certificates auto refresh time if Pulsar admin uses tls authentication.
- */
- private Duration autoCertRefreshTime = Duration.ofMinutes(5);
-
- public String getServiceUrl() {
- return this.serviceUrl;
- }
-
- public void setServiceUrl(String serviceUrl) {
- this.serviceUrl = serviceUrl;
- }
-
- public String getAuthPluginClassName() {
- return this.authPluginClassName;
- }
-
- public void setAuthPluginClassName(String authPluginClassName) {
- this.authPluginClassName = authPluginClassName;
- }
-
- public String getAuthParams() {
- return this.authParams;
- }
-
- public void setAuthParams(String authParams) {
- this.authParams = authParams;
- }
-
- public Map getAuthentication() {
- return this.authentication;
- }
-
- public void setAuthentication(Map authentication) {
- this.authentication = authentication;
- }
-
- public String getTlsTrustCertsFilePath() {
- return this.tlsTrustCertsFilePath;
- }
-
- public void setTlsTrustCertsFilePath(String tlsTrustCertsFilePath) {
- this.tlsTrustCertsFilePath = tlsTrustCertsFilePath;
- }
-
- public Boolean isTlsAllowInsecureConnection() {
- return this.tlsAllowInsecureConnection;
- }
-
- public void setTlsAllowInsecureConnection(Boolean tlsAllowInsecureConnection) {
- this.tlsAllowInsecureConnection = tlsAllowInsecureConnection;
- }
-
- public Boolean isTlsHostnameVerificationEnable() {
- return this.tlsHostnameVerificationEnable;
- }
-
- public void setTlsHostnameVerificationEnable(Boolean tlsHostnameVerificationEnable) {
- this.tlsHostnameVerificationEnable = tlsHostnameVerificationEnable;
- }
-
- public Boolean isUseKeyStoreTls() {
- return this.useKeyStoreTls;
- }
-
- public void setUseKeyStoreTls(Boolean useKeyStoreTls) {
- this.useKeyStoreTls = useKeyStoreTls;
- }
-
- public String getSslProvider() {
- return this.sslProvider;
- }
-
- public void setSslProvider(String sslProvider) {
- this.sslProvider = sslProvider;
- }
-
- public String getTlsTrustStoreType() {
- return this.tlsTrustStoreType;
- }
-
- public void setTlsTrustStoreType(String tlsTrustStoreType) {
- this.tlsTrustStoreType = tlsTrustStoreType;
- }
-
- public String getTlsTrustStorePath() {
- return this.tlsTrustStorePath;
- }
-
- public void setTlsTrustStorePath(String tlsTrustStorePath) {
- this.tlsTrustStorePath = tlsTrustStorePath;
- }
-
- public String getTlsTrustStorePassword() {
- return this.tlsTrustStorePassword;
- }
-
- public void setTlsTrustStorePassword(String tlsTrustStorePassword) {
- this.tlsTrustStorePassword = tlsTrustStorePassword;
- }
-
- public Set getTlsCiphers() {
- return this.tlsCiphers;
- }
-
- public void setTlsCiphers(Set tlsCiphers) {
- this.tlsCiphers = tlsCiphers;
- }
-
- public Set getTlsProtocols() {
- return this.tlsProtocols;
- }
-
- public void setTlsProtocols(Set tlsProtocols) {
- this.tlsProtocols = tlsProtocols;
- }
-
- public Duration getConnectionTimeout() {
- return this.connectionTimeout;
- }
-
- public void setConnectionTimeout(Duration connectionTimeout) {
- this.connectionTimeout = connectionTimeout;
- }
-
- public Duration getReadTimeout() {
- return this.readTimeout;
- }
-
- public void setReadTimeout(Duration readTimeout) {
- this.readTimeout = readTimeout;
- }
-
- public Duration getRequestTimeout() {
- return this.requestTimeout;
- }
-
- public void setRequestTimeout(Duration requestTimeout) {
- this.requestTimeout = requestTimeout;
- }
-
- public Duration getAutoCertRefreshTime() {
- return this.autoCertRefreshTime;
- }
-
- public void setAutoCertRefreshTime(Duration autoCertRefreshTime) {
- this.autoCertRefreshTime = autoCertRefreshTime;
- }
-
- public Map buildProperties() {
- if (StringUtils.hasText(this.getAuthParams()) && !CollectionUtils.isEmpty(this.getAuthentication())) {
- throw new IllegalArgumentException(
- "Cannot set both spring.pulsar.administration.authParams and spring.pulsar.administration.authentication.*");
- }
- PulsarProperties.Properties properties = new Properties();
-
- PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
- map.from(this::getServiceUrl).to(properties.in("serviceUrl"));
- map.from(this::getAuthPluginClassName).to(properties.in("authPluginClassName"));
- map.from(this::getAuthParams).to(properties.in("authParams"));
- map.from(this::getAuthentication).as(AuthParameterUtils::maybeConvertToEncodedParamString)
- .to(properties.in("authParams"));
- map.from(this::getTlsTrustCertsFilePath).to(properties.in("tlsTrustCertsFilePath"));
- map.from(this::isTlsAllowInsecureConnection).to(properties.in("tlsAllowInsecureConnection"));
- map.from(this::isTlsHostnameVerificationEnable).to(properties.in("tlsHostnameVerificationEnable"));
- map.from(this::isUseKeyStoreTls).to(properties.in("useKeyStoreTls"));
- map.from(this::getSslProvider).to(properties.in("sslProvider"));
- map.from(this::getTlsTrustStoreType).to(properties.in("tlsTrustStoreType"));
- map.from(this::getTlsTrustStorePath).to(properties.in("tlsTrustStorePath"));
- map.from(this::getTlsTrustStorePassword).to(properties.in("tlsTrustStorePassword"));
- map.from(this::getTlsCiphers).to(properties.in("tlsCiphers"));
- map.from(this::getTlsProtocols).to(properties.in("tlsProtocols"));
- map.from(this::getConnectionTimeout).asInt(Duration::toMillis).to(properties.in("connectionTimeoutMs"));
- map.from(this::getReadTimeout).asInt(Duration::toMillis).to(properties.in("readTimeoutMs"));
- map.from(this::getRequestTimeout).asInt(Duration::toMillis).to(properties.in("requestTimeoutMs"));
- map.from(this::getAutoCertRefreshTime).asInt(Duration::toSeconds)
- .to(properties.in("autoCertRefreshSeconds"));
-
- return properties;
- }
-
- }
-
- public static class Reader {
-
- /**
- * Topic names.
- */
- private List topicNames;
-
- /**
- * Size of a consumer's receiver queue.
- */
- private Integer receiverQueueSize;
-
- /**
- * Reader name.
- */
- private String readerName;
-
- /**
- * Subscription name.
- */
- private String subscriptionName;
-
- /**
- * Prefix of subscription role.
- */
- private String subscriptionRolePrefix;
-
- /**
- * Whether to read messages from a compacted topic rather than a full message
- * backlog of a topic.
- */
- private Boolean readCompacted;
-
- /**
- * Whether the first message to be returned is the one specified by messageId.
- */
- private Boolean resetIncludeHead;
-
- public List getTopicNames() {
- return this.topicNames;
- }
-
- public void setTopicNames(List topicNames) {
- this.topicNames = topicNames;
- }
-
- public Integer getReceiverQueueSize() {
- return this.receiverQueueSize;
- }
-
- public void setReceiverQueueSize(Integer receiverQueueSize) {
- this.receiverQueueSize = receiverQueueSize;
- }
-
- public String getReaderName() {
- return this.readerName;
- }
-
- public void setReaderName(String readerName) {
- this.readerName = readerName;
- }
-
- public String getSubscriptionName() {
- return this.subscriptionName;
- }
-
- public void setSubscriptionName(String subscriptionName) {
- this.subscriptionName = subscriptionName;
- }
-
- public String getSubscriptionRolePrefix() {
- return this.subscriptionRolePrefix;
- }
-
- public void setSubscriptionRolePrefix(String subscriptionRolePrefix) {
- this.subscriptionRolePrefix = subscriptionRolePrefix;
- }
-
- public Boolean getReadCompacted() {
- return this.readCompacted;
- }
-
- public void setReadCompacted(Boolean readCompacted) {
- this.readCompacted = readCompacted;
- }
-
- public Boolean getResetIncludeHead() {
- return this.resetIncludeHead;
- }
-
- public void setResetIncludeHead(Boolean resetIncludeHead) {
- this.resetIncludeHead = resetIncludeHead;
- }
-
- public Map buildProperties() {
-
- PulsarProperties.Properties properties = new Properties();
-
- PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
-
- map.from(this::getTopicNames).to(properties.in("topicNames"));
- map.from(this::getReceiverQueueSize).to(properties.in("receiverQueueSize"));
- map.from(this::getReaderName).to(properties.in("readerName"));
- map.from(this::getSubscriptionName).to(properties.in("subscriptionName"));
- map.from(this::getSubscriptionRolePrefix).to(properties.in("subscriptionRolePrefix"));
- map.from(this::getReadCompacted).to(properties.in("readCompacted"));
- map.from(this::getResetIncludeHead).to(properties.in("resetIncludeHead"));
-
- return properties;
- }
-
- }
-
- public static class Defaults {
-
- /**
- * List of mappings from message type to topic name and schema info to use as a
- * defaults when a topic name and/or schema is not explicitly specified when
- * producing or consuming messages of the mapped type.
- */
- private List typeMappings = new ArrayList<>();
-
- public List getTypeMappings() {
- return this.typeMappings;
- }
-
- public void setTypeMappings(List typeMappings) {
- this.typeMappings = typeMappings;
- }
-
- }
-
- /**
- * A mapping from message type to topic and/or schema info to use (at least one of
- * {@code topicName} or {@code schemaInfo} must be specified.
- * @param messageType the message type
- * @param topicName the topic name
- * @param schemaInfo the schema info
- */
- public record TypeMapping(Class> messageType, @Nullable String topicName, @Nullable SchemaInfo schemaInfo) {
- public TypeMapping {
- Objects.requireNonNull(messageType, "messageType must not be null");
- if (topicName == null && schemaInfo == null) {
- throw new IllegalArgumentException("At least one of topicName or schemaInfo must not be null");
- }
- }
- }
-
- /**
- * Represents a schema - holds enough information to construct an actual schema
- * instance.
- * @param schemaType schema type
- * @param messageKeyType message key type (required for key value type)
- */
- public record SchemaInfo(SchemaType schemaType, @Nullable Class> messageKeyType) {
- public SchemaInfo {
- Objects.requireNonNull(schemaType, "schemaType must not be null");
- if (schemaType == SchemaType.NONE) {
- throw new IllegalArgumentException("schemaType NONE not supported");
- }
- if (schemaType != SchemaType.KEY_VALUE && messageKeyType != null) {
- throw new IllegalArgumentException("messageKeyType can only be set when schemaType is KEY_VALUE");
- }
- }
- }
-
- static class Properties extends HashMap {
-
- java.util.function.Consumer in(String key) {
- return (value) -> put(key, value);
- }
-
- }
-
-}
diff --git a/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/PulsarReactiveAnnotationDrivenConfiguration.java b/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/PulsarReactiveAnnotationDrivenConfiguration.java
deleted file mode 100644
index 015c2df2..00000000
--- a/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/PulsarReactiveAnnotationDrivenConfiguration.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2022-2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.autoconfigure;
-
-import org.springframework.beans.factory.ObjectProvider;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.context.properties.PropertyMapper;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.pulsar.config.PulsarAnnotationSupportBeanNames;
-import org.springframework.pulsar.core.SchemaResolver;
-import org.springframework.pulsar.core.TopicResolver;
-import org.springframework.pulsar.reactive.config.DefaultReactivePulsarListenerContainerFactory;
-import org.springframework.pulsar.reactive.config.annotation.EnableReactivePulsar;
-import org.springframework.pulsar.reactive.core.ReactivePulsarConsumerFactory;
-import org.springframework.pulsar.reactive.listener.ReactivePulsarContainerProperties;
-
-/**
- * Configuration for Reactive Pulsar annotation-driven support.
- *
- * @author Christophe Bornet
- */
-@Configuration(proxyBeanMethods = false)
-@ConditionalOnClass(EnableReactivePulsar.class)
-public class PulsarReactiveAnnotationDrivenConfiguration {
-
- private final PulsarReactiveProperties properties;
-
- public PulsarReactiveAnnotationDrivenConfiguration(PulsarReactiveProperties properties) {
- this.properties = properties;
- }
-
- @Bean
- @ConditionalOnMissingBean(name = "reactivePulsarListenerContainerFactory")
- DefaultReactivePulsarListenerContainerFactory> reactivePulsarListenerContainerFactory(
- ObjectProvider> consumerFactoryProvider,
- SchemaResolver schemaResolver, TopicResolver topicResolver) {
-
- ReactivePulsarContainerProperties containerProperties = new ReactivePulsarContainerProperties<>();
- containerProperties.setSchemaResolver(schemaResolver);
- containerProperties.setTopicResolver(topicResolver);
- containerProperties.setSubscriptionType(this.properties.getConsumer().getSubscriptionType());
-
- PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
- PulsarReactiveProperties.Listener listenerProperties = this.properties.getListener();
- map.from(listenerProperties::getSchemaType).to(containerProperties::setSchemaType);
- map.from(listenerProperties::getHandlingTimeout).to(containerProperties::setHandlingTimeout);
- map.from(listenerProperties::getUseKeyOrderedProcessing).to(containerProperties::setUseKeyOrderedProcessing);
-
- return new DefaultReactivePulsarListenerContainerFactory<>(consumerFactoryProvider.getIfAvailable(),
- containerProperties);
- }
-
- @Configuration(proxyBeanMethods = false)
- @EnableReactivePulsar
- @ConditionalOnMissingBean(
- name = PulsarAnnotationSupportBeanNames.REACTIVE_PULSAR_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)
- static class EnableReactivePulsarConfiguration {
-
- }
-
-}
diff --git a/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/PulsarReactiveAutoConfiguration.java b/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/PulsarReactiveAutoConfiguration.java
deleted file mode 100644
index 73d1fca1..00000000
--- a/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/PulsarReactiveAutoConfiguration.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2022-2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.autoconfigure;
-
-import org.apache.pulsar.client.api.PulsarClient;
-import org.apache.pulsar.reactive.client.adapter.AdaptedReactivePulsarClientFactory;
-import org.apache.pulsar.reactive.client.adapter.ProducerCacheProvider;
-import org.apache.pulsar.reactive.client.api.ReactiveMessageSenderCache;
-import org.apache.pulsar.reactive.client.api.ReactivePulsarClient;
-import org.apache.pulsar.reactive.client.producercache.CaffeineProducerCacheProvider;
-
-import org.springframework.beans.factory.ObjectProvider;
-import org.springframework.boot.autoconfigure.AutoConfiguration;
-import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Import;
-import org.springframework.pulsar.core.SchemaResolver;
-import org.springframework.pulsar.core.TopicResolver;
-import org.springframework.pulsar.reactive.core.DefaultReactivePulsarConsumerFactory;
-import org.springframework.pulsar.reactive.core.DefaultReactivePulsarReaderFactory;
-import org.springframework.pulsar.reactive.core.DefaultReactivePulsarSenderFactory;
-import org.springframework.pulsar.reactive.core.ReactivePulsarConsumerFactory;
-import org.springframework.pulsar.reactive.core.ReactivePulsarReaderFactory;
-import org.springframework.pulsar.reactive.core.ReactivePulsarSenderFactory;
-import org.springframework.pulsar.reactive.core.ReactivePulsarTemplate;
-
-import com.github.benmanes.caffeine.cache.Caffeine;
-
-/**
- * {@link EnableAutoConfiguration Auto-configuration} for Apache Pulsar.
- *
- * @author Chris Bono
- * @author Christophe Bornet
- */
-@AutoConfiguration(after = PulsarAutoConfiguration.class)
-@ConditionalOnClass({ ReactivePulsarTemplate.class, ReactivePulsarClient.class })
-@EnableConfigurationProperties(PulsarReactiveProperties.class)
-@Import({ PulsarReactiveAnnotationDrivenConfiguration.class })
-public class PulsarReactiveAutoConfiguration {
-
- private final PulsarReactiveProperties properties;
-
- public PulsarReactiveAutoConfiguration(PulsarReactiveProperties properties) {
- this.properties = properties;
- }
-
- @Bean
- @ConditionalOnMissingBean
- public ReactivePulsarClient pulsarReactivePulsarClient(PulsarClient pulsarClient) {
- return AdaptedReactivePulsarClientFactory.create(pulsarClient);
- }
-
- @Bean
- @ConditionalOnMissingBean
- @ConditionalOnClass(CaffeineProducerCacheProvider.class)
- @ConditionalOnProperty(name = "spring.pulsar.reactive.sender.cache.enabled", havingValue = "true",
- matchIfMissing = true)
- public ProducerCacheProvider pulsarProducerCacheProvider() {
- PulsarReactiveProperties.Cache cache = this.properties.getSender().getCache();
- Caffeine caffeine = Caffeine.newBuilder().expireAfterAccess(cache.getExpireAfterAccess())
- .maximumSize(cache.getMaximumSize()).initialCapacity(cache.getInitialCapacity());
- return new CaffeineProducerCacheProvider(caffeine);
- }
-
- @Bean
- @ConditionalOnMissingBean
- @ConditionalOnProperty(name = "spring.pulsar.reactive.sender.cache.enabled", havingValue = "true",
- matchIfMissing = true)
- public ReactiveMessageSenderCache pulsarReactiveMessageSenderCache(
- ObjectProvider producerCacheProvider) {
- return producerCacheProvider.stream().findFirst().map(AdaptedReactivePulsarClientFactory::createCache)
- .orElseGet(AdaptedReactivePulsarClientFactory::createCache);
- }
-
- @Bean
- @ConditionalOnMissingBean
- public ReactivePulsarSenderFactory> reactivePulsarSenderFactory(ReactivePulsarClient pulsarReactivePulsarClient,
- ObjectProvider cache, TopicResolver topicResolver) {
- return new DefaultReactivePulsarSenderFactory<>(pulsarReactivePulsarClient,
- this.properties.buildReactiveMessageSenderSpec(), cache.getIfAvailable(), topicResolver);
- }
-
- @Bean
- @ConditionalOnMissingBean
- public ReactivePulsarConsumerFactory> reactivePulsarConsumerFactory(
- ReactivePulsarClient pulsarReactivePulsarClient) {
- return new DefaultReactivePulsarConsumerFactory<>(pulsarReactivePulsarClient,
- this.properties.buildReactiveMessageConsumerSpec());
- }
-
- @Bean
- @ConditionalOnMissingBean
- public ReactivePulsarReaderFactory> reactivePulsarReaderFactory(ReactivePulsarClient pulsarReactivePulsarClient) {
- return new DefaultReactivePulsarReaderFactory<>(pulsarReactivePulsarClient,
- this.properties.buildReactiveMessageReaderSpec());
- }
-
- @Bean
- @ConditionalOnMissingBean
- public ReactivePulsarTemplate> pulsarReactiveTemplate(ReactivePulsarSenderFactory> reactivePulsarSenderFactory,
- SchemaResolver schemaResolver, TopicResolver topicResolver) {
- return new ReactivePulsarTemplate<>(reactivePulsarSenderFactory, schemaResolver, topicResolver);
- }
-
-}
diff --git a/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/PulsarReactiveProperties.java b/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/PulsarReactiveProperties.java
deleted file mode 100644
index 50d3cbf7..00000000
--- a/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/PulsarReactiveProperties.java
+++ /dev/null
@@ -1,1118 +0,0 @@
-/*
- * Copyright 2022-2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.autoconfigure;
-
-import java.time.Duration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
-import java.util.regex.Pattern;
-
-import org.apache.pulsar.client.api.CompressionType;
-import org.apache.pulsar.client.api.ConsumerCryptoFailureAction;
-import org.apache.pulsar.client.api.DeadLetterPolicy;
-import org.apache.pulsar.client.api.HashingScheme;
-import org.apache.pulsar.client.api.MessageRoutingMode;
-import org.apache.pulsar.client.api.ProducerAccessMode;
-import org.apache.pulsar.client.api.ProducerCryptoFailureAction;
-import org.apache.pulsar.client.api.Range;
-import org.apache.pulsar.client.api.RegexSubscriptionMode;
-import org.apache.pulsar.client.api.SubscriptionInitialPosition;
-import org.apache.pulsar.client.api.SubscriptionMode;
-import org.apache.pulsar.client.api.SubscriptionType;
-import org.apache.pulsar.common.schema.SchemaType;
-import org.apache.pulsar.reactive.client.api.ImmutableReactiveMessageConsumerSpec;
-import org.apache.pulsar.reactive.client.api.ImmutableReactiveMessageReaderSpec;
-import org.apache.pulsar.reactive.client.api.ImmutableReactiveMessageSenderSpec;
-import org.apache.pulsar.reactive.client.api.MutableReactiveMessageConsumerSpec;
-import org.apache.pulsar.reactive.client.api.MutableReactiveMessageReaderSpec;
-import org.apache.pulsar.reactive.client.api.MutableReactiveMessageSenderSpec;
-import org.apache.pulsar.reactive.client.api.ReactiveMessageConsumerSpec;
-import org.apache.pulsar.reactive.client.api.ReactiveMessageReaderSpec;
-import org.apache.pulsar.reactive.client.api.ReactiveMessageSenderSpec;
-
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.boot.context.properties.NestedConfigurationProperty;
-import org.springframework.boot.context.properties.PropertyMapper;
-import org.springframework.lang.Nullable;
-import org.springframework.util.unit.DataSize;
-
-import reactor.core.scheduler.Schedulers;
-
-/**
- * Configuration properties for Spring for the Apache Pulsar reactive client.
- *
- * Users should refer to Pulsar reactive client documentation for complete descriptions of
- * these properties.
- *
- * @author Christophe Bornet
- */
-@ConfigurationProperties(prefix = "spring.pulsar.reactive")
-public class PulsarReactiveProperties {
-
- private final Sender sender = new Sender();
-
- private final Consumer consumer = new Consumer();
-
- private final Reader reader = new Reader();
-
- private final Listener listener = new Listener();
-
- public Sender getSender() {
- return this.sender;
- }
-
- public Consumer getConsumer() {
- return this.consumer;
- }
-
- public Reader getReader() {
- return this.reader;
- }
-
- public Listener getListener() {
- return this.listener;
- }
-
- public ReactiveMessageSenderSpec buildReactiveMessageSenderSpec() {
- return this.sender.buildReactiveMessageSenderSpec();
- }
-
- public ReactiveMessageReaderSpec buildReactiveMessageReaderSpec() {
- return this.reader.buildReactiveMessageReaderSpec();
- }
-
- public ReactiveMessageConsumerSpec buildReactiveMessageConsumerSpec() {
- return this.consumer.buildReactiveMessageConsumerSpec();
- }
-
- public static class Sender {
-
- /**
- * Topic the producer will publish to.
- */
- private String topicName;
-
- /**
- * Name for the producer. If not assigned, a unique name is generated.
- */
- private String producerName;
-
- /**
- * Time before a message has to be acknowledged by the broker.
- */
- private Duration sendTimeout = Duration.ofSeconds(30);
-
- /**
- * Maximum number of pending messages for the producer.
- */
- private Integer maxPendingMessages = 1000;
-
- /**
- * Maximum number of pending messages across all the partitions.
- */
- private Integer maxPendingMessagesAcrossPartitions = 50000;
-
- /**
- * Message routing mode for a partitioned producer.
- */
- private MessageRoutingMode messageRoutingMode = MessageRoutingMode.RoundRobinPartition;
-
- /**
- * Message hashing scheme to choose the partition to which the message is
- * published.
- */
- private HashingScheme hashingScheme = HashingScheme.JavaStringHash;
-
- /**
- * Action the producer will take in case of encryption failure.
- */
- private ProducerCryptoFailureAction cryptoFailureAction = ProducerCryptoFailureAction.FAIL;
-
- /**
- * Time period within which the messages sent will be batched.
- */
- private Duration batchingMaxPublishDelay = Duration.ofMillis(1);
-
- private Integer roundRobinRouterBatchingPartitionSwitchFrequency;
-
- /**
- * Maximum number of messages to be batched.
- */
- private Integer batchingMaxMessages = 1000;
-
- /**
- * Maximum number of bytes permitted in a batch.
- */
- private DataSize batchingMaxBytes = DataSize.ofKilobytes(128);
-
- /**
- * Whether to automatically batch messages.
- */
- private Boolean batchingEnabled = true;
-
- /**
- * Whether to split large-size messages into multiple chunks.
- */
- private Boolean chunkingEnabled = false;
-
- /**
- * Names of the public encryption keys to use when encrypting data.
- */
- private Set encryptionKeys = new HashSet<>();
-
- /**
- * Message compression type.
- */
- private CompressionType compressionType;
-
- /**
- * Baseline for the sequence ids for messages published by the producer.
- */
- @Nullable
- private Long initialSequenceId;
-
- /**
- * Whether partitioned producer automatically discover new partitions at runtime.
- */
- private Boolean autoUpdatePartitions = true;
-
- /**
- * Interval of partitions discovery updates.
- */
- private Duration autoUpdatePartitionsInterval = Duration.ofMinutes(1);
-
- /**
- * Whether the multiple schema mode is enabled.
- */
- private Boolean multiSchema = true;
-
- /**
- * Type of access to the topic the producer requires.
- */
- private ProducerAccessMode producerAccessMode = ProducerAccessMode.Shared;
-
- /**
- * Whether producers in Shared mode register and connect immediately to the owner
- * broker of each partition or start lazily on demand.
- */
- private Boolean lazyStartPartitionedProducers = false;
-
- /**
- * Map of properties to add to the producer.
- */
- private Map properties = new HashMap<>();
-
- private final Cache cache = new Cache();
-
- public String getTopicName() {
- return this.topicName;
- }
-
- public void setTopicName(String topicName) {
- this.topicName = topicName;
- }
-
- public String getProducerName() {
- return this.producerName;
- }
-
- public void setProducerName(String producerName) {
- this.producerName = producerName;
- }
-
- public Duration getSendTimeout() {
- return this.sendTimeout;
- }
-
- public void setSendTimeout(Duration sendTimeout) {
- this.sendTimeout = sendTimeout;
- }
-
- public Integer getMaxPendingMessages() {
- return this.maxPendingMessages;
- }
-
- public void setMaxPendingMessages(Integer maxPendingMessages) {
- this.maxPendingMessages = maxPendingMessages;
- }
-
- public Integer getMaxPendingMessagesAcrossPartitions() {
- return this.maxPendingMessagesAcrossPartitions;
- }
-
- public void setMaxPendingMessagesAcrossPartitions(Integer maxPendingMessagesAcrossPartitions) {
- this.maxPendingMessagesAcrossPartitions = maxPendingMessagesAcrossPartitions;
- }
-
- public MessageRoutingMode getMessageRoutingMode() {
- return this.messageRoutingMode;
- }
-
- public void setMessageRoutingMode(MessageRoutingMode messageRoutingMode) {
- this.messageRoutingMode = messageRoutingMode;
- }
-
- public HashingScheme getHashingScheme() {
- return this.hashingScheme;
- }
-
- public void setHashingScheme(HashingScheme hashingScheme) {
- this.hashingScheme = hashingScheme;
- }
-
- public ProducerCryptoFailureAction getCryptoFailureAction() {
- return this.cryptoFailureAction;
- }
-
- public void setCryptoFailureAction(ProducerCryptoFailureAction cryptoFailureAction) {
- this.cryptoFailureAction = cryptoFailureAction;
- }
-
- public Duration getBatchingMaxPublishDelay() {
- return this.batchingMaxPublishDelay;
- }
-
- public void setBatchingMaxPublishDelay(Duration batchingMaxPublishDelay) {
- this.batchingMaxPublishDelay = batchingMaxPublishDelay;
- }
-
- public Integer getRoundRobinRouterBatchingPartitionSwitchFrequency() {
- return this.roundRobinRouterBatchingPartitionSwitchFrequency;
- }
-
- public void setRoundRobinRouterBatchingPartitionSwitchFrequency(
- Integer roundRobinRouterBatchingPartitionSwitchFrequency) {
- this.roundRobinRouterBatchingPartitionSwitchFrequency = roundRobinRouterBatchingPartitionSwitchFrequency;
- }
-
- public Integer getBatchingMaxMessages() {
- return this.batchingMaxMessages;
- }
-
- public void setBatchingMaxMessages(Integer batchingMaxMessages) {
- this.batchingMaxMessages = batchingMaxMessages;
- }
-
- public DataSize getBatchingMaxBytes() {
- return this.batchingMaxBytes;
- }
-
- public void setBatchingMaxBytes(DataSize batchingMaxBytes) {
- this.batchingMaxBytes = batchingMaxBytes;
- }
-
- public Boolean getBatchingEnabled() {
- return this.batchingEnabled;
- }
-
- public void setBatchingEnabled(Boolean batchingEnabled) {
- this.batchingEnabled = batchingEnabled;
- }
-
- public Boolean getChunkingEnabled() {
- return this.chunkingEnabled;
- }
-
- public void setChunkingEnabled(Boolean chunkingEnabled) {
- this.chunkingEnabled = chunkingEnabled;
- }
-
- public Set getEncryptionKeys() {
- return this.encryptionKeys;
- }
-
- public void setEncryptionKeys(Set encryptionKeys) {
- this.encryptionKeys = encryptionKeys;
- }
-
- public CompressionType getCompressionType() {
- return this.compressionType;
- }
-
- public void setCompressionType(CompressionType compressionType) {
- this.compressionType = compressionType;
- }
-
- @Nullable
- public Long getInitialSequenceId() {
- return this.initialSequenceId;
- }
-
- public void setInitialSequenceId(@Nullable Long initialSequenceId) {
- this.initialSequenceId = initialSequenceId;
- }
-
- public Boolean getAutoUpdatePartitions() {
- return this.autoUpdatePartitions;
- }
-
- public void setAutoUpdatePartitions(Boolean autoUpdatePartitions) {
- this.autoUpdatePartitions = autoUpdatePartitions;
- }
-
- public Duration getAutoUpdatePartitionsInterval() {
- return this.autoUpdatePartitionsInterval;
- }
-
- public void setAutoUpdatePartitionsInterval(Duration autoUpdatePartitionsInterval) {
- this.autoUpdatePartitionsInterval = autoUpdatePartitionsInterval;
- }
-
- public Boolean getMultiSchema() {
- return this.multiSchema;
- }
-
- public void setMultiSchema(Boolean multiSchema) {
- this.multiSchema = multiSchema;
- }
-
- public ProducerAccessMode getProducerAccessMode() {
- return this.producerAccessMode;
- }
-
- public void setProducerAccessMode(ProducerAccessMode producerAccessMode) {
- this.producerAccessMode = producerAccessMode;
- }
-
- public Boolean getLazyStartPartitionedProducers() {
- return this.lazyStartPartitionedProducers;
- }
-
- public void setLazyStartPartitionedProducers(Boolean lazyStartPartitionedProducers) {
- this.lazyStartPartitionedProducers = lazyStartPartitionedProducers;
- }
-
- public Map getProperties() {
- return this.properties;
- }
-
- public void setProperties(Map properties) {
- this.properties = properties;
- }
-
- public Cache getCache() {
- return this.cache;
- }
-
- public ReactiveMessageSenderSpec buildReactiveMessageSenderSpec() {
- PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
-
- MutableReactiveMessageSenderSpec spec = new MutableReactiveMessageSenderSpec();
-
- map.from(this::getTopicName).to(spec::setTopicName);
- map.from(this::getProducerName).to(spec::setProducerName);
- map.from(this::getSendTimeout).to(spec::setSendTimeout);
- map.from(this::getMaxPendingMessages).to(spec::setMaxPendingMessages);
- map.from(this::getMaxPendingMessagesAcrossPartitions).to(spec::setMaxPendingMessagesAcrossPartitions);
- map.from(this::getMessageRoutingMode).to(spec::setMessageRoutingMode);
- map.from(this::getHashingScheme).to(spec::setHashingScheme);
- map.from(this::getCryptoFailureAction).to(spec::setCryptoFailureAction);
- map.from(this::getBatchingMaxPublishDelay).to(spec::setBatchingMaxPublishDelay);
- map.from(this::getRoundRobinRouterBatchingPartitionSwitchFrequency)
- .to(spec::setRoundRobinRouterBatchingPartitionSwitchFrequency);
- map.from(this::getBatchingMaxMessages).to(spec::setBatchingMaxMessages);
- map.from(this::getBatchingMaxBytes).asInt(DataSize::toBytes).to(spec::setBatchingMaxBytes);
- map.from(this::getBatchingEnabled).to(spec::setBatchingEnabled);
- map.from(this::getChunkingEnabled).to(spec::setChunkingEnabled);
- map.from(this::getEncryptionKeys).to(spec::setEncryptionKeys);
- map.from(this::getCompressionType).to(spec::setCompressionType);
- map.from(this::getInitialSequenceId).to(spec::setInitialSequenceId);
- map.from(this::getAutoUpdatePartitions).to(spec::setAutoUpdatePartitions);
- map.from(this::getAutoUpdatePartitionsInterval).to(spec::setAutoUpdatePartitionsInterval);
- map.from(this::getMultiSchema).to(spec::setMultiSchema);
- map.from(this::getProducerAccessMode).to(spec::setAccessMode);
- map.from(this::getLazyStartPartitionedProducers).to(spec::setLazyStartPartitionedProducers);
- map.from(this::getProperties).to(spec::setProperties);
-
- return new ImmutableReactiveMessageSenderSpec(spec);
- }
-
- }
-
- public static class Reader {
-
- private String[] topicNames;
-
- private String readerName;
-
- private String subscriptionName;
-
- private String generatedSubscriptionNamePrefix;
-
- private Integer receiverQueueSize;
-
- private Boolean readCompacted;
-
- private Range[] keyHashRanges;
-
- private ConsumerCryptoFailureAction cryptoFailureAction;
-
- public String[] getTopicNames() {
- return this.topicNames;
- }
-
- public void setTopicNames(String[] topicNames) {
- this.topicNames = topicNames;
- }
-
- public String getReaderName() {
- return this.readerName;
- }
-
- public void setReaderName(String readerName) {
- this.readerName = readerName;
- }
-
- public String getSubscriptionName() {
- return this.subscriptionName;
- }
-
- public void setSubscriptionName(String subscriptionName) {
- this.subscriptionName = subscriptionName;
- }
-
- public String getGeneratedSubscriptionNamePrefix() {
- return this.generatedSubscriptionNamePrefix;
- }
-
- public void setGeneratedSubscriptionNamePrefix(String generatedSubscriptionNamePrefix) {
- this.generatedSubscriptionNamePrefix = generatedSubscriptionNamePrefix;
- }
-
- public Integer getReceiverQueueSize() {
- return this.receiverQueueSize;
- }
-
- public void setReceiverQueueSize(Integer receiverQueueSize) {
- this.receiverQueueSize = receiverQueueSize;
- }
-
- public Boolean getReadCompacted() {
- return this.readCompacted;
- }
-
- public void setReadCompacted(Boolean readCompacted) {
- this.readCompacted = readCompacted;
- }
-
- public Range[] getKeyHashRanges() {
- return this.keyHashRanges;
- }
-
- public void setKeyHashRanges(Range[] keyHashRanges) {
- this.keyHashRanges = keyHashRanges;
- }
-
- public ConsumerCryptoFailureAction getCryptoFailureAction() {
- return this.cryptoFailureAction;
- }
-
- public void setCryptoFailureAction(ConsumerCryptoFailureAction cryptoFailureAction) {
- this.cryptoFailureAction = cryptoFailureAction;
- }
-
- public ReactiveMessageReaderSpec buildReactiveMessageReaderSpec() {
- PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
-
- MutableReactiveMessageReaderSpec spec = new MutableReactiveMessageReaderSpec();
-
- map.from(this::getTopicNames).as(List::of).to(spec::setTopicNames);
- map.from(this::getReaderName).to(spec::setReaderName);
- map.from(this::getSubscriptionName).to(spec::setSubscriptionName);
- map.from(this::getGeneratedSubscriptionNamePrefix).to(spec::setGeneratedSubscriptionNamePrefix);
- map.from(this::getReceiverQueueSize).to(spec::setReceiverQueueSize);
- map.from(this::getReadCompacted).to(spec::setReadCompacted);
- map.from(this::getKeyHashRanges).as(List::of).to(spec::setKeyHashRanges);
- map.from(this::getCryptoFailureAction).to(spec::setCryptoFailureAction);
-
- return new ImmutableReactiveMessageReaderSpec(spec);
- }
-
- }
-
- public static class Consumer {
-
- /**
- * Comma-separated list of topics the consumer subscribes to.
- */
- private String[] topics;
-
- /**
- * Pattern for topics the consumer subscribes to.
- */
- private Pattern topicsPattern;
-
- /**
- * Subscription name for the consumer.
- */
- private String subscriptionName;
-
- /**
- * Subscription type to be used when subscribing to a topic.
- */
- private SubscriptionType subscriptionType = SubscriptionType.Exclusive;
-
- /**
- * Map of properties to add to the subscription.
- */
- private SortedMap subscriptionProperties = new TreeMap<>();
-
- /**
- * Subscription mode to be used when subscribing to the topic.
- */
- private SubscriptionMode subscriptionMode = SubscriptionMode.Durable;
-
- /**
- * Number of messages that can be accumulated before the consumer calls "receive".
- */
- private Integer receiverQueueSize = 1000;
-
- /**
- * Time to group acknowledgements before sending them to the broker.
- */
- private Duration acknowledgementsGroupTime = Duration.ofMillis(100);
-
- /**
- * When set to true, ignores the acknowledge operation completion and makes it
- * asynchronous from the message consuming processing to improve performance by
- * allowing the acknowledges and message processing to interleave. Defaults to
- * true.
- */
- private Boolean acknowledgeAsynchronously = true;
-
- /**
- * Type of acknowledge scheduler.
- */
- private SchedulerType acknowledgeSchedulerType;
-
- /**
- * Delay before re-delivering messages that have failed to be processed.
- */
- private Duration negativeAckRedeliveryDelay = Duration.ofMinutes(1);
-
- /**
- * Configuration for the dead letter queue.
- */
- @NestedConfigurationProperty
- private DeadLetterPolicy deadLetterPolicy;
-
- /**
- * Whether the retry letter topic is enabled.
- */
- private Boolean retryLetterTopicEnable = false;
-
- /**
- * Maximum number of messages that a consumer can be pushed at once from a broker
- * across all partitions.
- */
- private Integer maxTotalReceiverQueueSizeAcrossPartitions = 50000;
-
- /**
- * Consumer name to identify a particular consumer from the topic stats.
- */
- private String consumerName;
-
- /**
- * Timeout for unacked messages to be redelivered.
- */
- private Duration ackTimeout = Duration.ZERO;
-
- /**
- * Precision for the ack timeout messages tracker.
- */
- private Duration ackTimeoutTickTime = Duration.ofSeconds(1);
-
- /**
- * Priority level for shared subscription consumers.
- */
- private Integer priorityLevel = 0;
-
- /**
- * Action the consumer will take in case of decryption failure.
- */
- private ConsumerCryptoFailureAction cryptoFailureAction = ConsumerCryptoFailureAction.FAIL;
-
- /**
- * Map of properties to add to the consumer.
- */
- private SortedMap properties = new TreeMap<>();
-
- /**
- * Whether to read messages from the compacted topic rather than the full message
- * backlog.
- */
- private Boolean readCompacted = false;
-
- /**
- * Whether batch index acknowledgement is enabled.
- */
- private Boolean batchIndexAckEnabled = false;
-
- /**
- * Position where to initialize a newly created subscription.
- */
- private SubscriptionInitialPosition subscriptionInitialPosition = SubscriptionInitialPosition.Latest;
-
- /**
- * Auto-discovery period for topics when topic pattern is used.
- */
- private Duration topicsPatternAutoDiscoveryPeriod = Duration.ofMinutes(1);
-
- /**
- * Determines which topics the consumer should be subscribed to when using pattern
- * subscriptions.
- */
- private RegexSubscriptionMode topicsPatternSubscriptionMode = RegexSubscriptionMode.PersistentOnly;
-
- /**
- * Whether the consumer auto-subscribes for partition increase. This is only for
- * partitioned consumers.
- */
- private Boolean autoUpdatePartitions = true;
-
- private Duration autoUpdatePartitionsInterval = Duration.ofMinutes(1);
-
- /**
- * Whether to replicate subscription state.
- */
- private Boolean replicateSubscriptionState = false;
-
- /**
- * Whether to automatically drop outstanding un-acked messages if the queue is
- * full.
- */
- private Boolean autoAckOldestChunkedMessageOnQueueFull = true;
-
- /**
- * Maximum number of chunked messages to be kept in memory.
- */
- private Integer maxPendingChunkedMessage = 10;
-
- /**
- * Time to expire incomplete chunks if the consumer won't be able to receive all
- * chunks before in milliseconds.
- */
- private Duration expireTimeOfIncompleteChunkedMessage = Duration.ofMinutes(1);
-
- public String[] getTopics() {
- return this.topics;
- }
-
- public void setTopics(String[] topics) {
- this.topics = topics;
- }
-
- public Pattern getTopicsPattern() {
- return this.topicsPattern;
- }
-
- public void setTopicsPattern(Pattern topicsPattern) {
- this.topicsPattern = topicsPattern;
- }
-
- public String getSubscriptionName() {
- return this.subscriptionName;
- }
-
- public void setSubscriptionName(String subscriptionName) {
- this.subscriptionName = subscriptionName;
- }
-
- public SubscriptionType getSubscriptionType() {
- return this.subscriptionType;
- }
-
- public void setSubscriptionType(SubscriptionType subscriptionType) {
- this.subscriptionType = subscriptionType;
- }
-
- public SortedMap getSubscriptionProperties() {
- return this.subscriptionProperties;
- }
-
- public void setSubscriptionProperties(SortedMap subscriptionProperties) {
- this.subscriptionProperties = subscriptionProperties;
- }
-
- public SubscriptionMode getSubscriptionMode() {
- return this.subscriptionMode;
- }
-
- public void setSubscriptionMode(SubscriptionMode subscriptionMode) {
- this.subscriptionMode = subscriptionMode;
- }
-
- public Integer getReceiverQueueSize() {
- return this.receiverQueueSize;
- }
-
- public void setReceiverQueueSize(Integer receiverQueueSize) {
- this.receiverQueueSize = receiverQueueSize;
- }
-
- public Duration getAcknowledgementsGroupTime() {
- return this.acknowledgementsGroupTime;
- }
-
- public void setAcknowledgementsGroupTime(Duration acknowledgementsGroupTime) {
- this.acknowledgementsGroupTime = acknowledgementsGroupTime;
- }
-
- public Boolean getAcknowledgeAsynchronously() {
- return this.acknowledgeAsynchronously;
- }
-
- public void setAcknowledgeAsynchronously(Boolean acknowledgeAsynchronously) {
- this.acknowledgeAsynchronously = acknowledgeAsynchronously;
- }
-
- public SchedulerType getAcknowledgeSchedulerType() {
- return this.acknowledgeSchedulerType;
- }
-
- public void setAcknowledgeSchedulerType(SchedulerType acknowledgeSchedulerType) {
- this.acknowledgeSchedulerType = acknowledgeSchedulerType;
- }
-
- public Duration getNegativeAckRedeliveryDelay() {
- return this.negativeAckRedeliveryDelay;
- }
-
- public void setNegativeAckRedeliveryDelay(Duration negativeAckRedeliveryDelay) {
- this.negativeAckRedeliveryDelay = negativeAckRedeliveryDelay;
- }
-
- public DeadLetterPolicy getDeadLetterPolicy() {
- return this.deadLetterPolicy;
- }
-
- public void setDeadLetterPolicy(DeadLetterPolicy deadLetterPolicy) {
- this.deadLetterPolicy = deadLetterPolicy;
- }
-
- public Boolean getRetryLetterTopicEnable() {
- return this.retryLetterTopicEnable;
- }
-
- public void setRetryLetterTopicEnable(Boolean retryLetterTopicEnable) {
- this.retryLetterTopicEnable = retryLetterTopicEnable;
- }
-
- public Integer getMaxTotalReceiverQueueSizeAcrossPartitions() {
- return this.maxTotalReceiverQueueSizeAcrossPartitions;
- }
-
- public void setMaxTotalReceiverQueueSizeAcrossPartitions(Integer maxTotalReceiverQueueSizeAcrossPartitions) {
- this.maxTotalReceiverQueueSizeAcrossPartitions = maxTotalReceiverQueueSizeAcrossPartitions;
- }
-
- public String getConsumerName() {
- return this.consumerName;
- }
-
- public void setConsumerName(String consumerName) {
- this.consumerName = consumerName;
- }
-
- public Duration getAckTimeout() {
- return this.ackTimeout;
- }
-
- public void setAckTimeout(Duration ackTimeout) {
- this.ackTimeout = ackTimeout;
- }
-
- public Duration getAckTimeoutTickTime() {
- return this.ackTimeoutTickTime;
- }
-
- public void setAckTimeoutTickTime(Duration ackTimeoutTickTime) {
- this.ackTimeoutTickTime = ackTimeoutTickTime;
- }
-
- public Integer getPriorityLevel() {
- return this.priorityLevel;
- }
-
- public void setPriorityLevel(Integer priorityLevel) {
- this.priorityLevel = priorityLevel;
- }
-
- public ConsumerCryptoFailureAction getCryptoFailureAction() {
- return this.cryptoFailureAction;
- }
-
- public void setCryptoFailureAction(ConsumerCryptoFailureAction cryptoFailureAction) {
- this.cryptoFailureAction = cryptoFailureAction;
- }
-
- public SortedMap getProperties() {
- return this.properties;
- }
-
- public void setProperties(SortedMap properties) {
- this.properties = properties;
- }
-
- public Boolean getReadCompacted() {
- return this.readCompacted;
- }
-
- public void setReadCompacted(Boolean readCompacted) {
- this.readCompacted = readCompacted;
- }
-
- public Boolean getBatchIndexAckEnabled() {
- return this.batchIndexAckEnabled;
- }
-
- public void setBatchIndexAckEnabled(Boolean batchIndexAckEnabled) {
- this.batchIndexAckEnabled = batchIndexAckEnabled;
- }
-
- public SubscriptionInitialPosition getSubscriptionInitialPosition() {
- return this.subscriptionInitialPosition;
- }
-
- public void setSubscriptionInitialPosition(SubscriptionInitialPosition subscriptionInitialPosition) {
- this.subscriptionInitialPosition = subscriptionInitialPosition;
- }
-
- public Duration getTopicsPatternAutoDiscoveryPeriod() {
- return this.topicsPatternAutoDiscoveryPeriod;
- }
-
- public void setTopicsPatternAutoDiscoveryPeriod(Duration topicsPatternAutoDiscoveryPeriod) {
- this.topicsPatternAutoDiscoveryPeriod = topicsPatternAutoDiscoveryPeriod;
- }
-
- public RegexSubscriptionMode getTopicsPatternSubscriptionMode() {
- return this.topicsPatternSubscriptionMode;
- }
-
- public void setTopicsPatternSubscriptionMode(RegexSubscriptionMode topicsPatternSubscriptionMode) {
- this.topicsPatternSubscriptionMode = topicsPatternSubscriptionMode;
- }
-
- public Boolean getAutoUpdatePartitions() {
- return this.autoUpdatePartitions;
- }
-
- public void setAutoUpdatePartitions(Boolean autoUpdatePartitions) {
- this.autoUpdatePartitions = autoUpdatePartitions;
- }
-
- public Duration getAutoUpdatePartitionsInterval() {
- return this.autoUpdatePartitionsInterval;
- }
-
- public void setAutoUpdatePartitionsInterval(Duration autoUpdatePartitionsInterval) {
- this.autoUpdatePartitionsInterval = autoUpdatePartitionsInterval;
- }
-
- public Boolean getReplicateSubscriptionState() {
- return this.replicateSubscriptionState;
- }
-
- public void setReplicateSubscriptionState(Boolean replicateSubscriptionState) {
- this.replicateSubscriptionState = replicateSubscriptionState;
- }
-
- public Boolean getAutoAckOldestChunkedMessageOnQueueFull() {
- return this.autoAckOldestChunkedMessageOnQueueFull;
- }
-
- public void setAutoAckOldestChunkedMessageOnQueueFull(Boolean autoAckOldestChunkedMessageOnQueueFull) {
- this.autoAckOldestChunkedMessageOnQueueFull = autoAckOldestChunkedMessageOnQueueFull;
- }
-
- public Integer getMaxPendingChunkedMessage() {
- return this.maxPendingChunkedMessage;
- }
-
- public void setMaxPendingChunkedMessage(Integer maxPendingChunkedMessage) {
- this.maxPendingChunkedMessage = maxPendingChunkedMessage;
- }
-
- public Duration getExpireTimeOfIncompleteChunkedMessage() {
- return this.expireTimeOfIncompleteChunkedMessage;
- }
-
- public void setExpireTimeOfIncompleteChunkedMessage(Duration expireTimeOfIncompleteChunkedMessage) {
- this.expireTimeOfIncompleteChunkedMessage = expireTimeOfIncompleteChunkedMessage;
- }
-
- public ReactiveMessageConsumerSpec buildReactiveMessageConsumerSpec() {
-
- MutableReactiveMessageConsumerSpec spec = new MutableReactiveMessageConsumerSpec();
-
- PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
-
- map.from(this::getTopics).as(List::of).to(spec::setTopicNames);
- map.from(this::getTopicsPattern).to(spec::setTopicsPattern);
- map.from(this::getSubscriptionName).to(spec::setSubscriptionName);
- map.from(this::getSubscriptionType).to(spec::setSubscriptionType);
- map.from(this::getSubscriptionProperties).to(spec::setSubscriptionProperties);
- map.from(this::getSubscriptionMode).to(spec::setSubscriptionMode);
- map.from(this::getReceiverQueueSize).to(spec::setReceiverQueueSize);
- map.from(this::getAcknowledgementsGroupTime).to(spec::setAcknowledgementsGroupTime);
- map.from(this::getAcknowledgeAsynchronously).to(spec::setAcknowledgeAsynchronously);
- map.from(this::getAcknowledgeSchedulerType).as((scheduler) -> switch (scheduler) {
- case boundedElastic -> Schedulers.boundedElastic();
- case parallel -> Schedulers.parallel();
- case single -> Schedulers.single();
- case immediate -> Schedulers.immediate();
- }).to(spec::setAcknowledgeScheduler);
- map.from(this::getNegativeAckRedeliveryDelay).to(spec::setNegativeAckRedeliveryDelay);
- map.from(this::getDeadLetterPolicy).to(spec::setDeadLetterPolicy);
- map.from(this::getRetryLetterTopicEnable).to(spec::setRetryLetterTopicEnable);
- map.from(this::getMaxTotalReceiverQueueSizeAcrossPartitions)
- .to(spec::setMaxTotalReceiverQueueSizeAcrossPartitions);
- map.from(this::getConsumerName).to(spec::setConsumerName);
- map.from(this::getAckTimeout).to(spec::setAckTimeout);
- map.from(this::getAckTimeoutTickTime).to(spec::setAckTimeoutTickTime);
- map.from(this::getPriorityLevel).to(spec::setPriorityLevel);
- map.from(this::getCryptoFailureAction).to(spec::setCryptoFailureAction);
- map.from(this::getProperties).to(spec::setProperties);
- map.from(this::getReadCompacted).to(spec::setReadCompacted);
- map.from(this::getBatchIndexAckEnabled).to(spec::setBatchIndexAckEnabled);
- map.from(this::getSubscriptionInitialPosition).to(spec::setSubscriptionInitialPosition);
- map.from(this::getTopicsPatternAutoDiscoveryPeriod).to(spec::setTopicsPatternAutoDiscoveryPeriod);
- map.from(this::getTopicsPatternSubscriptionMode).to(spec::setTopicsPatternSubscriptionMode);
- map.from(this::getAutoUpdatePartitions).to(spec::setAutoUpdatePartitions);
- map.from(this::getAutoUpdatePartitionsInterval).to(spec::setAutoUpdatePartitionsInterval);
- map.from(this::getReplicateSubscriptionState).to(spec::setReplicateSubscriptionState);
- map.from(this::getAutoAckOldestChunkedMessageOnQueueFull)
- .to(spec::setAutoAckOldestChunkedMessageOnQueueFull);
- map.from(this::getMaxPendingChunkedMessage).to(spec::setMaxPendingChunkedMessage);
- map.from(this::getExpireTimeOfIncompleteChunkedMessage).to(spec::setExpireTimeOfIncompleteChunkedMessage);
- return new ImmutableReactiveMessageConsumerSpec(spec);
- }
-
- }
-
- public enum SchedulerType {
-
- /**
- * The reactor.core.scheduler.BoundedElasticScheduler.
- */
- boundedElastic,
-
- /**
- * The reactor.core.scheduler.ParallelScheduler.
- */
- parallel,
-
- /**
- * The reactor.core.scheduler.SingleScheduler.
- */
- single,
-
- /**
- * The reactor.core.scheduler.ImmediateScheduler.
- */
- immediate
-
- }
-
- public static class Cache {
-
- /** Time period to expire unused entries in the cache. */
- private Duration expireAfterAccess = Duration.ofMinutes(1);
-
- /** Maximum size of cache (entries). */
- private Long maximumSize = 1000L;
-
- /** Initial size of cache. */
- private Integer initialCapacity = 50;
-
- public Duration getExpireAfterAccess() {
- return this.expireAfterAccess;
- }
-
- public void setExpireAfterAccess(Duration expireAfterAccess) {
- this.expireAfterAccess = expireAfterAccess;
- }
-
- public Long getMaximumSize() {
- return this.maximumSize;
- }
-
- public void setMaximumSize(Long maximumSize) {
- this.maximumSize = maximumSize;
- }
-
- public Integer getInitialCapacity() {
- return this.initialCapacity;
- }
-
- public void setInitialCapacity(Integer initialCapacity) {
- this.initialCapacity = initialCapacity;
- }
-
- }
-
- public static class Listener {
-
- /**
- * SchemaType of the consumed messages.
- */
- private SchemaType schemaType;
-
- /**
- * Duration to wait before the message handling times out.
- */
- private Duration handlingTimeout = Duration.ofMinutes(2);
-
- /**
- * Whether per-key message ordering should be maintained when concurrent
- * processing is used.
- */
- private Boolean useKeyOrderedProcessing = false;
-
- public SchemaType getSchemaType() {
- return this.schemaType;
- }
-
- public void setSchemaType(SchemaType schemaType) {
- this.schemaType = schemaType;
- }
-
- public Duration getHandlingTimeout() {
- return this.handlingTimeout;
- }
-
- public void setHandlingTimeout(Duration handlingTimeout) {
- this.handlingTimeout = handlingTimeout;
- }
-
- public Boolean getUseKeyOrderedProcessing() {
- return this.useKeyOrderedProcessing;
- }
-
- public void setUseKeyOrderedProcessing(Boolean useKeyOrderedProcessing) {
- this.useKeyOrderedProcessing = useKeyOrderedProcessing;
- }
-
- }
-
-}
diff --git a/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/WellKnownAuthParameters.java b/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/WellKnownAuthParameters.java
deleted file mode 100644
index d8d409af..00000000
--- a/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/WellKnownAuthParameters.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2022-2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.autoconfigure;
-
-import java.util.Arrays;
-import java.util.Map;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-/**
- * Utility class to map Pulsar auth parameters to well-known keys.
- *
- * @author Alexander Preuß
- */
-enum WellKnownAuthParameters {
-
- TENANT_DOMAIN("tenantDomain"),
-
- TENANT_SERVICE("tenantService"),
-
- PROVIDER_DOMAIN("providerDomain"),
-
- PRIVATE_KEY("privateKey"),
-
- PRIVATE_KEY_PATH("privateKeyPath"),
-
- KEY_ID("keyId"),
-
- AUTO_PREFETCH_ENABLED("autoPrefetchEnabled"),
-
- ATHENZ_CONF_PATH("athenzConfPath"),
-
- PRINCIPAL_HEADER("principalHeader"),
-
- ROLE_HEADER("roleHeader"),
-
- ZTS_URL("ztsUrl"),
-
- USER_ID("userId"),
-
- PASSWORD("password"),
-
- KEY_STORE_TYPE("keyStoreType"),
-
- KEY_STORE_PATH("keyStorePath"),
-
- KEY_STORE_PASSWORD("keyStorePassword"),
-
- TYPE("type"),
-
- ISSUER_URL("issuerUrl"),
-
- AUDIENCE("audience"),
-
- SCOPE("scope"),
-
- SASL_JAAS_CLIENT_SECTION_NAME("saslJaasClientSectionName"),
-
- SERVER_TYPE("serverType"),
-
- TLS_CERT_FILE("tlsCertFile"),
-
- TLS_KEY_FILE("tlsKeyFile"),
-
- TOKEN("token");
-
- private static final Map LOWER_CASE_TO_CAMEL_CASE = Arrays.stream(values())
- .map(WellKnownAuthParameters::getCamelCaseKey)
- .collect(Collectors.toMap(String::toLowerCase, Function.identity()));
-
- private final String camelCaseKey;
-
- WellKnownAuthParameters(String camelCaseKey) {
- this.camelCaseKey = camelCaseKey;
- }
-
- String getCamelCaseKey() {
- return this.camelCaseKey;
- }
-
- /**
- * Returns the camel-cased version a Pulsar auth parameter or the given key in case it
- * is not part of the well-known ones.
- * @param lowerCaseKey the lower-cased auth parameter
- * @return the camel-cased auth parameter, or the lowerCaseKey if the parameter is not
- * found.
- */
- public static String toCamelCaseKey(String lowerCaseKey) {
- return LOWER_CASE_TO_CAMEL_CASE.getOrDefault(lowerCaseKey, lowerCaseKey);
- }
-
-}
diff --git a/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/package-info.java b/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/package-info.java
deleted file mode 100644
index 89928137..00000000
--- a/spring-pulsar-spring-boot-autoconfigure/src/main/java/org/springframework/pulsar/autoconfigure/package-info.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * Package containing the Spring Boot
- * {@link org.springframework.boot.autoconfigure.AutoConfiguration} for the Spring for
- * Apache Pulsar framework.
- */
-@NonNullApi
-@NonNullFields
-package org.springframework.pulsar.autoconfigure;
-
-import org.springframework.lang.NonNullApi;
-import org.springframework.lang.NonNullFields;
diff --git a/spring-pulsar-spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-pulsar-spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json
deleted file mode 100644
index 6fe034ef..00000000
--- a/spring-pulsar-spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "groups": [],
- "properties": [
- {
- "name": "spring.pulsar.function.enabled",
- "type": "java.lang.Boolean",
- "description": "Whether to enable function support.",
- "defaultValue": true
- },
- {
- "name": "spring.pulsar.producer.cache.enabled",
- "type": "java.lang.Boolean",
- "description": "Whether to enable caching in the PulsarProducerFactory.",
- "defaultValue": true
- },
- {
- "name": "spring.pulsar.reactive.sender.cache.enabled",
- "type": "java.lang.Boolean",
- "description": "Whether to enable caching in the ReactivePulsarSenderFactory.",
- "defaultValue": true
- }
- ],
- "hints": []
-}
diff --git a/spring-pulsar-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-pulsar-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
deleted file mode 100644
index 93aa9162..00000000
--- a/spring-pulsar-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
+++ /dev/null
@@ -1,2 +0,0 @@
-org.springframework.pulsar.autoconfigure.PulsarAutoConfiguration
-org.springframework.pulsar.autoconfigure.PulsarReactiveAutoConfiguration
diff --git a/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/AuthParameterUtilsTests.java b/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/AuthParameterUtilsTests.java
deleted file mode 100644
index d43865fc..00000000
--- a/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/AuthParameterUtilsTests.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2022-2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.autoconfigure;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.jupiter.params.provider.Arguments.arguments;
-
-import java.util.Collections;
-import java.util.Map;
-import java.util.stream.Stream;
-
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.Arguments;
-import org.junit.jupiter.params.provider.MethodSource;
-
-/**
- * Tests for {@link AuthParameterUtils}.
- *
- * @author Alexander Preuß
- */
-public class AuthParameterUtilsTests {
-
- @ParameterizedTest(name = "{0}")
- @MethodSource("encodedParamStringConversionProvider")
- void encodedParamStringConversion(String testName, Map authParamsMap) {
- String encodedAuthParamString = AuthParameterUtils.maybeConvertToEncodedParamString(authParamsMap);
- if (authParamsMap == null || authParamsMap.isEmpty()) {
- assertThat(encodedAuthParamString).isNull();
- }
- else {
- assertThat(encodedAuthParamString).isEqualTo("{\"audience\":\"urn:sn:pulsar:abc:xyz\","
- + "\"issuerUrl\":\"https://auth.server.cloud\",\"privateKey\":\"file://Users/xyz/key.json\"}");
- }
- }
-
- private static Stream encodedParamStringConversionProvider() {
- return Stream.of(arguments("null", null), arguments("empty", Collections.emptyMap()),
- arguments("camelCase",
- Map.of("issuerUrl", "https://auth.server.cloud", "privateKey", "file://Users/xyz/key.json",
- "audience", "urn:sn:pulsar:abc:xyz")),
- arguments("kebabCase",
- Map.of("issuer-url", "https://auth.server.cloud", "private-key", "file://Users/xyz/key.json",
- "audience", "urn:sn:pulsar:abc:xyz")),
- arguments("lowerCase",
- Map.of("issuerurl", "https://auth.server.cloud", "privatekey", "file://Users/xyz/key.json",
- "audience", "urn:sn:pulsar:abc:xyz")),
- arguments("mixed", Map.of("issuerurl", "https://auth.server.cloud", "private-key",
- "file://Users/xyz/key.json", "audience", "urn:sn:pulsar:abc:xyz")));
- }
-
-}
diff --git a/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/PulsarAutoConfigurationTests.java b/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/PulsarAutoConfigurationTests.java
deleted file mode 100644
index 1951e298..00000000
--- a/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/PulsarAutoConfigurationTests.java
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * Copyright 2022-2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.autoconfigure;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.entry;
-import static org.mockito.Mockito.mock;
-
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.pulsar.client.api.PulsarClient;
-import org.apache.pulsar.client.api.Schema;
-import org.apache.pulsar.client.api.SubscriptionInitialPosition;
-import org.apache.pulsar.client.api.SubscriptionType;
-import org.apache.pulsar.client.api.interceptor.ProducerInterceptor;
-import org.apache.pulsar.common.schema.KeyValueEncodingType;
-import org.apache.pulsar.common.schema.SchemaType;
-import org.assertj.core.api.AbstractObjectAssert;
-import org.assertj.core.api.InstanceOfAssertFactories;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-import org.springframework.boot.autoconfigure.AutoConfigurations;
-import org.springframework.boot.test.context.FilteredClassLoader;
-import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
-import org.springframework.boot.test.context.runner.ApplicationContextRunner;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.annotation.Order;
-import org.springframework.pulsar.annotation.EnablePulsar;
-import org.springframework.pulsar.annotation.PulsarBootstrapConfiguration;
-import org.springframework.pulsar.annotation.PulsarListenerAnnotationBeanPostProcessor;
-import org.springframework.pulsar.config.ConcurrentPulsarListenerContainerFactory;
-import org.springframework.pulsar.config.PulsarClientFactoryBean;
-import org.springframework.pulsar.config.PulsarListenerContainerFactory;
-import org.springframework.pulsar.config.PulsarListenerEndpointRegistry;
-import org.springframework.pulsar.core.CachingPulsarProducerFactory;
-import org.springframework.pulsar.core.DefaultPulsarProducerFactory;
-import org.springframework.pulsar.core.DefaultPulsarReaderFactory;
-import org.springframework.pulsar.core.DefaultSchemaResolver;
-import org.springframework.pulsar.core.DefaultTopicResolver;
-import org.springframework.pulsar.core.PulsarAdministration;
-import org.springframework.pulsar.core.PulsarConsumerFactory;
-import org.springframework.pulsar.core.PulsarProducerFactory;
-import org.springframework.pulsar.core.PulsarReaderFactory;
-import org.springframework.pulsar.core.PulsarTemplate;
-import org.springframework.pulsar.core.SchemaResolver;
-import org.springframework.pulsar.core.SchemaResolver.SchemaResolverCustomizer;
-import org.springframework.pulsar.core.TopicResolver;
-import org.springframework.pulsar.function.PulsarFunctionAdministration;
-import org.springframework.pulsar.listener.AckMode;
-import org.springframework.pulsar.listener.PulsarContainerProperties;
-
-import com.github.benmanes.caffeine.cache.Caffeine;
-
-/**
- * Autoconfiguration tests for {@link PulsarAutoConfiguration}.
- *
- * @author Chris Bono
- * @author Alexander Preuß
- * @author Soby Chacko
- */
-@SuppressWarnings("unchecked")
-class PulsarAutoConfigurationTests {
-
- private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
- .withConfiguration(AutoConfigurations.of(PulsarAutoConfiguration.class));
-
- @Test
- void autoConfigurationSkippedWhenPulsarTemplateNotOnClasspath() {
- this.contextRunner.withClassLoader(new FilteredClassLoader(PulsarTemplate.class))
- .run((context) -> assertThat(context).hasNotFailed().doesNotHaveBean(PulsarAutoConfiguration.class));
- }
-
- @Test
- void annotationDrivenConfigurationSkippedWhenEnablePulsarAnnotationNotOnClasspath() {
- this.contextRunner.withClassLoader(new FilteredClassLoader(EnablePulsar.class))
- .run((context) -> assertThat(context).hasNotFailed()
- .doesNotHaveBean(PulsarAnnotationDrivenConfiguration.class));
- }
-
- @Test
- void bootstrapConfigurationSkippedWhenCustomPulsarListenerAnnotationProcessorDefined() {
- this.contextRunner
- .withBean("org.springframework.pulsar.config.internalPulsarListenerAnnotationProcessor", String.class,
- () -> "someFauxBean")
- .run((context) -> assertThat(context).hasNotFailed()
- .doesNotHaveBean(PulsarBootstrapConfiguration.class));
- }
-
- @Test
- void defaultBeansAreAutoConfigured() {
- this.contextRunner.run((context) -> assertThat(context).hasNotFailed()
- .hasSingleBean(PulsarClientFactoryBean.class).hasSingleBean(PulsarProducerFactory.class)
- .hasSingleBean(PulsarTemplate.class).hasSingleBean(PulsarConsumerFactory.class)
- .hasSingleBean(ConcurrentPulsarListenerContainerFactory.class)
- .hasSingleBean(PulsarListenerAnnotationBeanPostProcessor.class)
- .hasSingleBean(PulsarListenerEndpointRegistry.class).hasSingleBean(PulsarAdministration.class)
- .hasSingleBean(DefaultSchemaResolver.class).hasSingleBean(DefaultTopicResolver.class));
- }
-
- @Test
- void customPulsarClientFactoryBeanIsRespected() {
- PulsarClientFactoryBean clientFactoryBean = new PulsarClientFactoryBean(
- new PulsarProperties().buildClientProperties());
- this.contextRunner
- .withBean("customPulsarClientFactoryBean", PulsarClientFactoryBean.class, () -> clientFactoryBean)
- .run((context) -> assertThat(context)
- .getBean("&customPulsarClientFactoryBean", PulsarClientFactoryBean.class)
- .isSameAs(clientFactoryBean));
- }
-
- @Test
- void customSchemaResolverIsRespected() {
- SchemaResolver customSchemaResolver = mock(SchemaResolver.class);
- this.contextRunner.withBean("customSchemaResolver", SchemaResolver.class, () -> customSchemaResolver)
- .run((context) -> assertThat(context).hasNotFailed().getBean(SchemaResolver.class)
- .isSameAs(customSchemaResolver));
- }
-
- @Test
- void defaultSchemaResolverCanBeCustomized() {
- record Foo() {
- }
- SchemaResolverCustomizer customizer = (sr) -> sr.addCustomSchemaMapping(Foo.class,
- Schema.STRING);
- this.contextRunner.withBean("schemaResolverCustomizer", SchemaResolverCustomizer.class, () -> customizer)
- .run((context) -> assertThat(context).hasNotFailed().getBean(DefaultSchemaResolver.class)
- .extracting(DefaultSchemaResolver::getCustomSchemaMappings, InstanceOfAssertFactories.MAP)
- .containsEntry(Foo.class, Schema.STRING));
- }
-
- @Test
- void customTopicResolverIsRespected() {
- TopicResolver customTopicResolver = mock(TopicResolver.class);
- this.contextRunner.withBean("customTopicResolver", TopicResolver.class, () -> customTopicResolver)
- .run((context) -> assertThat(context).hasNotFailed().getBean(TopicResolver.class)
- .isSameAs(customTopicResolver));
- }
-
- @Test
- void customPulsarProducerFactoryIsRespected() {
- PulsarProducerFactory producerFactory = mock(PulsarProducerFactory.class);
- this.contextRunner.withBean("customPulsarProducerFactory", PulsarProducerFactory.class, () -> producerFactory)
- .run((context) -> assertThat(context).hasNotFailed().getBean(PulsarProducerFactory.class)
- .isSameAs(producerFactory));
- }
-
- @Test
- void customPulsarTemplateIsRespected() {
- PulsarTemplate template = mock(PulsarTemplate.class);
- this.contextRunner.withBean("customPulsarTemplate", PulsarTemplate.class, () -> template)
- .run((context) -> assertThat(context).hasNotFailed().getBean(PulsarTemplate.class).isSameAs(template));
- }
-
- @Test
- void beansAreInjectedInPulsarTemplate() {
- PulsarProducerFactory> producerFactory = mock(PulsarProducerFactory.class);
- SchemaResolver schemaResolver = mock(SchemaResolver.class);
- TopicResolver topicResolver = mock(TopicResolver.class);
- this.contextRunner.withBean("customPulsarProducerFactory", PulsarProducerFactory.class, () -> producerFactory)
- .withBean("schemaResolver", SchemaResolver.class, () -> schemaResolver)
- .withBean("topicResolver", TopicResolver.class, () -> topicResolver)
- .run((context -> assertThat(context).hasNotFailed().getBean(PulsarTemplate.class)
- .hasFieldOrPropertyWithValue("producerFactory", producerFactory)
- .hasFieldOrPropertyWithValue("schemaResolver", schemaResolver)
- .hasFieldOrPropertyWithValue("topicResolver", topicResolver)));
- }
-
- @Test
- void customPulsarConsumerFactoryIsRespected() {
- PulsarConsumerFactory consumerFactory = mock(PulsarConsumerFactory.class);
- this.contextRunner.withBean("customPulsarConsumerFactory", PulsarConsumerFactory.class, () -> consumerFactory)
- .run((context) -> assertThat(context).hasNotFailed().getBean(PulsarConsumerFactory.class)
- .isSameAs(consumerFactory));
- }
-
- @Test
- void pulsarConsumerFactoryWithEnumPropertyValue() {
- this.contextRunner.withPropertyValues("spring.pulsar.consumer.subscription-initial-position=earliest")
- .run((context -> assertThat(context).hasNotFailed().getBean(PulsarConsumerFactory.class)
- .extracting("consumerConfig").hasFieldOrPropertyWithValue("subscriptionInitialPosition",
- SubscriptionInitialPosition.Earliest)));
- }
-
- @Test
- void customPulsarListenerContainerFactoryIsRespected() {
- PulsarListenerContainerFactory listenerContainerFactory = mock(PulsarListenerContainerFactory.class);
- this.contextRunner
- .withBean("pulsarListenerContainerFactory", PulsarListenerContainerFactory.class,
- () -> listenerContainerFactory)
- .run((context) -> assertThat(context).hasNotFailed().getBean(PulsarListenerContainerFactory.class)
- .isSameAs(listenerContainerFactory));
- }
-
- @Test
- void beansAreInjectedInPulsarListenerContainerFactory() {
- PulsarConsumerFactory> consumerFactory = mock(PulsarConsumerFactory.class);
- SchemaResolver schemaResolver = mock(SchemaResolver.class);
- TopicResolver topicResolver = mock(TopicResolver.class);
- this.contextRunner.withBean("pulsarConsumerFactory", PulsarConsumerFactory.class, () -> consumerFactory)
- .withBean("schemaResolver", SchemaResolver.class, () -> schemaResolver)
- .withBean("topicResolver", TopicResolver.class, () -> topicResolver)
- .run((context -> assertThat(context).hasNotFailed()
- .getBean(ConcurrentPulsarListenerContainerFactory.class)
- .hasFieldOrPropertyWithValue("consumerFactory", consumerFactory)
- .extracting(ConcurrentPulsarListenerContainerFactory::getContainerProperties)
- .hasFieldOrPropertyWithValue("schemaResolver", schemaResolver)
- .hasFieldOrPropertyWithValue("topicResolver", topicResolver)));
- }
-
- @Test
- void customPulsarListenerAnnotationBeanPostProcessorIsRespected() {
- PulsarListenerAnnotationBeanPostProcessor listenerAnnotationBeanPostProcessor = mock(
- PulsarListenerAnnotationBeanPostProcessor.class);
- this.contextRunner
- .withBean("org.springframework.pulsar.config.internalPulsarListenerAnnotationProcessor",
- PulsarListenerAnnotationBeanPostProcessor.class, () -> listenerAnnotationBeanPostProcessor)
- .run((context) -> assertThat(context).hasNotFailed()
- .getBean(PulsarListenerAnnotationBeanPostProcessor.class)
- .isSameAs(listenerAnnotationBeanPostProcessor));
- }
-
- @Test
- void customPulsarAdministrationIsRespected() {
- PulsarAdministration pulsarAdministration = mock(PulsarAdministration.class);
- this.contextRunner
- .withBean("customPulsarAdministration", PulsarAdministration.class, () -> pulsarAdministration)
- .run((context) -> assertThat(context).hasNotFailed().getBean(PulsarAdministration.class)
- .isSameAs(pulsarAdministration));
- }
-
- @Test
- void customProducerInterceptorIsUsedInPulsarTemplate() {
- ProducerInterceptor interceptor = mock(ProducerInterceptor.class);
- this.contextRunner.withBean("customProducerInterceptor", ProducerInterceptor.class, () -> interceptor)
- .run((context -> assertThat(context).hasNotFailed().getBean(PulsarTemplate.class)
- .extracting("interceptors")
- .asInstanceOf(InstanceOfAssertFactories.list(ProducerInterceptor.class))
- .contains(interceptor)));
- }
-
- @Test
- void customProducerInterceptorsOrderedProperly() {
- this.contextRunner.withUserConfiguration(InterceptorTestConfiguration.class)
- .run((context -> assertThat(context).hasNotFailed().getBean(PulsarTemplate.class)
- .extracting("interceptors")
- .asInstanceOf(InstanceOfAssertFactories.list(ProducerInterceptor.class))
- .containsExactly(InterceptorTestConfiguration.interceptorBar,
- InterceptorTestConfiguration.interceptorFoo)));
- }
-
- @Test
- void listenerPropertiesAreHonored() {
- contextRunner
- .withPropertyValues("spring.pulsar.listener.ack-mode=manual", "spring.pulsar.listener.schema-type=avro",
- "spring.pulsar.listener.max-num-messages=10", "spring.pulsar.listener.max-num-bytes=101B",
- "spring.pulsar.listener.batch-timeout=50ms", "spring.pulsar.consumer.subscription-type=shared")
- .run((context -> {
- AbstractObjectAssert, PulsarContainerProperties> properties = assertThat(context).hasNotFailed()
- .getBean(ConcurrentPulsarListenerContainerFactory.class)
- .extracting(ConcurrentPulsarListenerContainerFactory::getContainerProperties);
- properties.extracting(PulsarContainerProperties::getAckMode).isEqualTo(AckMode.MANUAL);
- properties.extracting(PulsarContainerProperties::getSchemaType).isEqualTo(SchemaType.AVRO);
- properties.extracting(PulsarContainerProperties::getMaxNumMessages).isEqualTo(10);
- properties.extracting(PulsarContainerProperties::getMaxNumBytes).isEqualTo(101);
- properties.extracting(PulsarContainerProperties::getBatchTimeoutMillis).isEqualTo(50);
- properties.extracting(PulsarContainerProperties::getSubscriptionType)
- .isEqualTo(SubscriptionType.Shared);
- }));
- }
-
- @Nested
- class DefaultsTypeMappingsTests {
-
- @Test
- void topicMappingsAreAddedToTopicResolver() {
- contextRunner
- .withPropertyValues(
- "spring.pulsar.defaults.type-mappings[0].message-type=%s".formatted(Foo.class.getName()),
- "spring.pulsar.defaults.type-mappings[0].topic-name=foo-topic",
- "spring.pulsar.defaults.type-mappings[1].message-type=%s".formatted(String.class.getName()),
- "spring.pulsar.defaults.type-mappings[1].topic-name=string-topic")
- .run((context -> assertThat(context).hasNotFailed().getBean(TopicResolver.class)
- .asInstanceOf(InstanceOfAssertFactories.type(DefaultTopicResolver.class))
- .extracting(DefaultTopicResolver::getCustomTopicMappings, InstanceOfAssertFactories.MAP)
- .containsOnly(entry(Foo.class, "foo-topic"), entry(String.class, "string-topic"))));
- }
-
- @Test
- void schemaMappingForPrimitiveIsAddedToSchemaResolver() {
- contextRunner
- .withPropertyValues(
- "spring.pulsar.defaults.type-mappings[0].message-type=%s".formatted(Foo.class.getName()),
- "spring.pulsar.defaults.type-mappings[0].schema-info.schema-type=STRING")
- .run((context -> assertThat(context).hasNotFailed().getBean(SchemaResolver.class)
- .asInstanceOf(InstanceOfAssertFactories.type(DefaultSchemaResolver.class))
- .extracting(DefaultSchemaResolver::getCustomSchemaMappings, InstanceOfAssertFactories.MAP)
- .containsOnly(entry(Foo.class, Schema.STRING))));
- }
-
- @Test
- void schemaMappingForStructIsAddedToSchemaResolver() {
- contextRunner
- .withPropertyValues(
- "spring.pulsar.defaults.type-mappings[0].message-type=%s".formatted(Foo.class.getName()),
- "spring.pulsar.defaults.type-mappings[0].schema-info.schema-type=JSON")
- .run((context -> assertThat(context).hasNotFailed().getBean(SchemaResolver.class)
- .asInstanceOf(InstanceOfAssertFactories.type(DefaultSchemaResolver.class))
- .extracting(DefaultSchemaResolver::getCustomSchemaMappings,
- InstanceOfAssertFactories.map(Class.class, Schema.class))
- .hasEntrySatisfying(Foo.class,
- (schema) -> assertSchemaEquals(schema, Schema.JSON(Foo.class)))));
- }
-
- @Test
- void schemaMappingForKeyValueIsAddedToSchemaResolver() {
- contextRunner
- .withPropertyValues(
- "spring.pulsar.defaults.type-mappings[0].message-type=%s".formatted(Foo.class.getName()),
- "spring.pulsar.defaults.type-mappings[0].schema-info.schema-type=%s"
- .formatted(SchemaType.KEY_VALUE.name()),
- "spring.pulsar.defaults.type-mappings[0].schema-info.message-key-type=%s"
- .formatted(String.class.getName()))
- .run((context -> assertThat(context).hasNotFailed().getBean(SchemaResolver.class)
- .asInstanceOf(InstanceOfAssertFactories.type(DefaultSchemaResolver.class))
- .extracting(DefaultSchemaResolver::getCustomSchemaMappings,
- InstanceOfAssertFactories.map(Class.class, Schema.class))
- .hasEntrySatisfying(Foo.class, (schema) -> assertSchemaEquals(schema, Schema
- .KeyValue(Schema.STRING, Schema.JSON(Foo.class), KeyValueEncodingType.INLINE)))));
- }
-
- private void assertSchemaEquals(Schema> left, Schema> right) {
- assertThat(left.getSchemaInfo()).isEqualTo(right.getSchemaInfo());
- }
-
- record Foo() {
- }
-
- }
-
- @Nested
- class ClientAutoConfigurationTests {
-
- @Test
- void authParamMapConvertedToEncodedParamString() {
- contextRunner.withPropertyValues(
- "spring.pulsar.client.auth-plugin-class-name=org.apache.pulsar.client.impl.auth.AuthenticationBasic",
- "spring.pulsar.client.authentication.userId=username",
- "spring.pulsar.client.authentication.password=topsecret")
- .run((context -> assertThat(context).hasNotFailed().getBean(PulsarClientFactoryBean.class)
- .extracting("config", InstanceOfAssertFactories.map(String.class, Object.class))
- .doesNotContainKey("authParamMap").doesNotContainKey("userId").doesNotContainKey("password")
- .containsEntry("authParams", "{\"password\":\"topsecret\",\"userId\":\"username\"}")));
- }
-
- }
-
- @Nested
- class FunctionAutoConfigurationTests {
-
- @Test
- void functionSupportEnabledByDefault() {
- // NOTE: hasNoNullFieldsOrProperties() ensures object providers set
- contextRunner.run(context -> assertThat(context).hasNotFailed().getBean(PulsarFunctionAdministration.class)
- .hasFieldOrPropertyWithValue("failFast", Boolean.TRUE)
- .hasFieldOrPropertyWithValue("propagateFailures", Boolean.TRUE)
- .hasFieldOrPropertyWithValue("propagateStopFailures", Boolean.FALSE).hasNoNullFieldsOrProperties()
- .extracting("pulsarAdministration").isSameAs(context.getBean(PulsarAdministration.class)));
- }
-
- @Test
- void functionSupportCanBeConfigured() {
- contextRunner
- .withPropertyValues("spring.pulsar.function.fail-fast=false",
- "spring.pulsar.function.propagate-failures=false",
- "spring.pulsar.function.propagate-stop-failures=true")
- .run(context -> assertThat(context).hasNotFailed().getBean(PulsarFunctionAdministration.class)
- .hasFieldOrPropertyWithValue("failFast", Boolean.FALSE)
- .hasFieldOrPropertyWithValue("propagateFailures", Boolean.FALSE)
- .hasFieldOrPropertyWithValue("propagateStopFailures", Boolean.TRUE));
- }
-
- @Test
- void functionSupportCanBeDisabled() {
- contextRunner.withPropertyValues("spring.pulsar.function.enabled=false").run(
- context -> assertThat(context).hasNotFailed().doesNotHaveBean(PulsarFunctionAdministration.class));
- }
-
- @Test
- void customFunctionAdminIsRespected() {
- PulsarFunctionAdministration customFunctionAdmin = mock(PulsarFunctionAdministration.class);
- contextRunner.withBean(PulsarFunctionAdministration.class, () -> customFunctionAdmin)
- .run(context -> assertThat(context).hasNotFailed().getBean(PulsarFunctionAdministration.class)
- .isSameAs(customFunctionAdmin));
- }
-
- }
-
- @Nested
- class ObservationAutoConfigurationTests {
-
- @Test
- void templateObservationsEnabledByDefault() {
- contextRunner.run((context -> assertThat(context).getBean(PulsarTemplate.class)
- .hasFieldOrPropertyWithValue("observationEnabled", true)));
- }
-
- @Test
- void templateObservationsEnabledExplicitly() {
- contextRunner.withPropertyValues("spring.pulsar.template.observations-enabled=true")
- .run((context -> assertThat(context).getBean(PulsarTemplate.class)
- .hasFieldOrPropertyWithValue("observationEnabled", true)));
- }
-
- @Test
- void templateObservationsCanBeDisabled() {
- contextRunner.withPropertyValues("spring.pulsar.template.observations-enabled=false")
- .run((context -> assertThat(context).getBean(PulsarTemplate.class)
- .hasFieldOrPropertyWithValue("observationEnabled", false)));
- }
-
- @Test
- void listenerObservationsEnabledByDefault() {
- contextRunner.run((context -> assertThat(context).getBean(ConcurrentPulsarListenerContainerFactory.class)
- .hasFieldOrPropertyWithValue("containerProperties.observationEnabled", true)));
- }
-
- @Test
- void listenerObservationsEnabledExplicitly() {
- contextRunner.withPropertyValues("spring.pulsar.listener.observations-enabled=true")
- .run((context -> assertThat(context).getBean(ConcurrentPulsarListenerContainerFactory.class)
- .hasFieldOrPropertyWithValue("containerProperties.observationEnabled", true)));
- }
-
- @Test
- void listenerObservationsCanBeDisabled() {
- contextRunner.withPropertyValues("spring.pulsar.listener.observations-enabled=false")
- .run((context -> assertThat(context).getBean(ConcurrentPulsarListenerContainerFactory.class)
- .hasFieldOrPropertyWithValue("containerProperties.observationEnabled", false)));
- }
-
- }
-
- @Nested
- class ProducerFactoryAutoConfigurationTests {
-
- @Test
- void cachingProducerFactoryEnabledByDefault() {
- contextRunner.run((context) -> assertHasProducerFactoryOfType(CachingPulsarProducerFactory.class, context));
- }
-
- @Test
- void nonCachingProducerFactoryCanBeEnabled() {
- contextRunner.withPropertyValues("spring.pulsar.producer.cache.enabled=false")
- .run((context -> assertHasProducerFactoryOfType(DefaultPulsarProducerFactory.class, context)));
- }
-
- @Test
- void cachingProducerFactoryCanBeEnabled() {
- contextRunner.withPropertyValues("spring.pulsar.producer.cache.enabled=true")
- .run((context -> assertHasProducerFactoryOfType(CachingPulsarProducerFactory.class, context)));
- }
-
- @Test
- void cachingEnabledAndCaffeineNotOnClasspath() {
- contextRunner.withClassLoader(new FilteredClassLoader(Caffeine.class))
- .withPropertyValues("spring.pulsar.producer.cache.enabled=true")
- .run((context -> assertHasProducerFactoryOfType(CachingPulsarProducerFactory.class, context)));
- }
-
- @Test
- void cachingProducerFactoryCanBeConfigured() {
- contextRunner
- .withPropertyValues("spring.pulsar.producer.cache.expire-after-access=100s",
- "spring.pulsar.producer.cache.maximum-size=5150",
- "spring.pulsar.producer.cache.initial-capacity=200")
- .run((context -> assertThat(context).hasNotFailed().getBean(PulsarProducerFactory.class)
- .extracting("producerCache.cache.cache").hasFieldOrPropertyWithValue("maximum", 5150L)
- .hasFieldOrPropertyWithValue("expiresAfterAccessNanos", TimeUnit.SECONDS.toNanos(100))));
- }
-
- @Test
- void beansAreInjectedInNonCachingProducerFactory() {
- contextRunner.withPropertyValues("spring.pulsar.producer.cache.enabled=false")
- .run((context -> assertThat(context).hasNotFailed().getBean(DefaultPulsarProducerFactory.class)
- .hasFieldOrPropertyWithValue("pulsarClient", context.getBean(PulsarClient.class))
- .hasFieldOrPropertyWithValue("topicResolver", context.getBean(TopicResolver.class))));
- }
-
- @Test
- void beansAreInjectedInCachingProducerFactory() {
- contextRunner.withPropertyValues("spring.pulsar.producer.cache.enabled=true")
- .run((context -> assertThat(context).hasNotFailed().getBean(CachingPulsarProducerFactory.class)
- .hasFieldOrPropertyWithValue("pulsarClient", context.getBean(PulsarClient.class))
- .hasFieldOrPropertyWithValue("topicResolver", context.getBean(TopicResolver.class))));
- }
-
- private void assertHasProducerFactoryOfType(Class> producerFactoryType,
- AssertableApplicationContext context) {
- assertThat(context).hasNotFailed().hasSingleBean(PulsarProducerFactory.class)
- .getBean(PulsarProducerFactory.class).isExactlyInstanceOf(producerFactoryType);
- }
-
- }
-
- @Nested
- class ReaderFactoryAutoConfigurationTests {
-
- @Test
- void readerFactoryIsAutoConfiguredByDefault() {
- contextRunner.run((context) -> assertThat(context).hasNotFailed().hasSingleBean(PulsarReaderFactory.class)
- .getBean(PulsarReaderFactory.class).isExactlyInstanceOf(DefaultPulsarReaderFactory.class));
- }
-
- @Test
- void readerFactoryCanBeConfigured() {
- contextRunner.withPropertyValues("spring.pulsar.reader.topic-names=foo",
- "spring.pulsar.reader.receiver-queue-size=200", "spring.pulsar.reader.reader-name=test-reader",
- "spring.pulsar.reader.subscription-name=test-subscription",
- "spring.pulsar.reader.subscription-role-prefix=test-prefix",
- "spring.pulsar.reader.read-compacted=true", "spring.pulsar.reader.reset-include-head=true")
- .run((context -> assertThat(context).hasNotFailed().getBean(PulsarReaderFactory.class)
- .extracting("readerConfig").hasFieldOrPropertyWithValue("topicNames", List.of("foo"))
- .hasFieldOrPropertyWithValue("receiverQueueSize", 200)
- .hasFieldOrPropertyWithValue("readerName", "test-reader")
- .hasFieldOrPropertyWithValue("subscriptionName", "test-subscription")
- .hasFieldOrPropertyWithValue("subscriptionRolePrefix", "test-prefix")
- .hasFieldOrPropertyWithValue("readCompacted", true)
- .hasFieldOrPropertyWithValue("resetIncludeHead", true)));
- }
-
- }
-
- @Configuration(proxyBeanMethods = false)
- static class InterceptorTestConfiguration {
-
- static ProducerInterceptor interceptorFoo = mock(ProducerInterceptor.class);
- static ProducerInterceptor interceptorBar = mock(ProducerInterceptor.class);
-
- @Bean
- @Order(200)
- ProducerInterceptor interceptorFoo() {
- return interceptorFoo;
- }
-
- @Bean
- @Order(100)
- ProducerInterceptor interceptorBar() {
- return interceptorBar;
- }
-
- }
-
-}
diff --git a/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/PulsarPropertiesTests.java b/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/PulsarPropertiesTests.java
deleted file mode 100644
index 61242166..00000000
--- a/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/PulsarPropertiesTests.java
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- * Copyright 2022-2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.autoconfigure;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
-import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
-import static org.assertj.core.api.Assertions.assertThatNoException;
-import static org.assertj.core.api.Assertions.assertThatRuntimeException;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.pulsar.client.admin.PulsarAdmin;
-import org.apache.pulsar.client.api.CompressionType;
-import org.apache.pulsar.client.api.ConsumerCryptoFailureAction;
-import org.apache.pulsar.client.api.DeadLetterPolicy;
-import org.apache.pulsar.client.api.HashingScheme;
-import org.apache.pulsar.client.api.MessageRoutingMode;
-import org.apache.pulsar.client.api.ProducerAccessMode;
-import org.apache.pulsar.client.api.ProducerCryptoFailureAction;
-import org.apache.pulsar.client.api.ProxyProtocol;
-import org.apache.pulsar.client.api.PulsarClient;
-import org.apache.pulsar.client.api.RegexSubscriptionMode;
-import org.apache.pulsar.client.api.SubscriptionInitialPosition;
-import org.apache.pulsar.client.api.SubscriptionMode;
-import org.apache.pulsar.client.api.SubscriptionType;
-import org.apache.pulsar.client.impl.conf.ConfigurationDataUtils;
-import org.apache.pulsar.client.impl.conf.ConsumerConfigurationData;
-import org.apache.pulsar.client.impl.conf.ProducerConfigurationData;
-import org.apache.pulsar.client.impl.conf.ReaderConfigurationData;
-import org.apache.pulsar.common.schema.SchemaType;
-import org.assertj.core.api.InstanceOfAssertFactories;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-import org.springframework.boot.context.properties.bind.BindException;
-import org.springframework.boot.context.properties.bind.Bindable;
-import org.springframework.boot.context.properties.bind.Binder;
-import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
-import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
-import org.springframework.pulsar.autoconfigure.PulsarProperties.SchemaInfo;
-import org.springframework.pulsar.autoconfigure.PulsarProperties.TypeMapping;
-
-/**
- * Unit tests for {@link PulsarProperties}.
- *
- * @author Chris Bono
- * @author Christophe Bornet
- * @author Soby Chacko
- */
-public class PulsarPropertiesTests {
-
- private final PulsarProperties properties = new PulsarProperties();
-
- private void bind(Map map) {
- ConfigurationPropertySource source = new MapConfigurationPropertySource(map);
- new Binder(source).bind("spring.pulsar", Bindable.ofInstance(this.properties));
- }
-
- @Nested
- class ClientPropertiesTests {
-
- private final String authPluginClassName = "org.apache.pulsar.client.impl.auth.AuthenticationToken";
-
- private final String authParamsStr = "{\"token\":\"1234\"}";
-
- private final String authToken = "1234";
-
- @Test
- void clientProperties() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.client.service-url", "my-service-url");
- props.put("spring.pulsar.client.listener-name", "my-listener");
- props.put("spring.pulsar.client.operation-timeout", "1s");
- props.put("spring.pulsar.client.lookup-timeout", "2s");
- props.put("spring.pulsar.client.num-io-threads", "3");
- props.put("spring.pulsar.client.num-listener-threads", "4");
- props.put("spring.pulsar.client.num-connections-per-broker", "5");
- props.put("spring.pulsar.client.use-tcp-no-delay", "false");
- props.put("spring.pulsar.client.use-tls", "true");
- props.put("spring.pulsar.client.tls-hostname-verification-enable", "true");
- props.put("spring.pulsar.client.tls-trust-certs-file-path", "my-trust-certs-file-path");
- props.put("spring.pulsar.client.tls-allow-insecure-connection", "true");
- props.put("spring.pulsar.client.use-key-store-tls", "true");
- props.put("spring.pulsar.client.ssl-provider", "my-ssl-provider");
- props.put("spring.pulsar.client.tls-trust-store-type", "my-trust-store-type");
- props.put("spring.pulsar.client.tls-trust-store-path", "my-trust-store-path");
- props.put("spring.pulsar.client.tls-trust-store-password", "my-trust-store-password");
- props.put("spring.pulsar.client.tls-ciphers[0]", "my-tls-cipher");
- props.put("spring.pulsar.client.tls-protocols[0]", "my-tls-protocol");
- props.put("spring.pulsar.client.stats-interval", "6s");
- props.put("spring.pulsar.client.max-concurrent-lookup-request", "7");
- props.put("spring.pulsar.client.max-lookup-request", "8");
- props.put("spring.pulsar.client.max-lookup-redirects", "9");
- props.put("spring.pulsar.client.max-number-of-rejected-request-per-connection", "10");
- props.put("spring.pulsar.client.keep-alive-interval", "11s");
- props.put("spring.pulsar.client.connection-timeout", "12s");
- props.put("spring.pulsar.client.request-timeout", "13s");
- props.put("spring.pulsar.client.initial-backoff-interval", "14s");
- props.put("spring.pulsar.client.max-backoff-interval", "15s");
- props.put("spring.pulsar.client.enable-busy-wait", "true");
- props.put("spring.pulsar.client.memory-limit", "16B");
- props.put("spring.pulsar.client.proxy-service-url", "my-proxy-service-url");
- props.put("spring.pulsar.client.proxy-protocol", "sni");
- props.put("spring.pulsar.client.enable-transaction", "true");
- props.put("spring.pulsar.client.dns-lookup-bind-address", "my-dns-lookup-bind-address");
- props.put("spring.pulsar.client.dns-lookup-bind-port", "17");
- props.put("spring.pulsar.client.socks5-proxy-address", "my-socks5-proxy-address");
- props.put("spring.pulsar.client.socks5-proxy-username", "my-socks5-proxy-username");
- props.put("spring.pulsar.client.socks5-proxy-password", "my-socks5-proxy-password");
-
- bind(props);
- Map clientProps = properties.buildClientProperties();
-
- // Verify that the props can be loaded in a ClientBuilder
- assertThatNoException().isThrownBy(() -> PulsarClient.builder().loadConf(clientProps));
-
- assertThat(clientProps).containsEntry("serviceUrl", "my-service-url")
- .containsEntry("listenerName", "my-listener").containsEntry("operationTimeoutMs", 1_000L)
- .containsEntry("lookupTimeoutMs", 2_000L).containsEntry("numIoThreads", 3)
- .containsEntry("numListenerThreads", 4).containsEntry("connectionsPerBroker", 5)
- .containsEntry("useTcpNoDelay", false).containsEntry("useTls", true)
- .containsEntry("tlsHostnameVerificationEnable", true)
- .containsEntry("tlsTrustCertsFilePath", "my-trust-certs-file-path")
- .containsEntry("tlsAllowInsecureConnection", true).containsEntry("useKeyStoreTls", true)
- .containsEntry("sslProvider", "my-ssl-provider")
- .containsEntry("tlsTrustStoreType", "my-trust-store-type")
- .containsEntry("tlsTrustStorePath", "my-trust-store-path")
- .containsEntry("tlsTrustStorePassword", "my-trust-store-password")
- .hasEntrySatisfying("tlsCiphers",
- ciphers -> assertThat(ciphers)
- .asInstanceOf(InstanceOfAssertFactories.collection(String.class))
- .containsExactly("my-tls-cipher"))
- .hasEntrySatisfying("tlsProtocols",
- protocols -> assertThat(protocols)
- .asInstanceOf(InstanceOfAssertFactories.collection(String.class))
- .containsExactly("my-tls-protocol"))
- .containsEntry("statsIntervalSeconds", 6L).containsEntry("concurrentLookupRequest", 7)
- .containsEntry("maxLookupRequest", 8).containsEntry("maxLookupRedirects", 9)
- .containsEntry("maxNumberOfRejectedRequestPerConnection", 10)
- .containsEntry("keepAliveIntervalSeconds", 11).containsEntry("connectionTimeoutMs", 12_000)
- .containsEntry("requestTimeoutMs", 13_000)
- .containsEntry("initialBackoffIntervalNanos", 14_000_000_000L)
- .containsEntry("maxBackoffIntervalNanos", 15_000_000_000L).containsEntry("enableBusyWait", true)
- .containsEntry("memoryLimitBytes", 16L).containsEntry("proxyServiceUrl", "my-proxy-service-url")
- .containsEntry("proxyProtocol", ProxyProtocol.SNI).containsEntry("enableTransaction", true)
- .containsEntry("dnsLookupBindAddress", "my-dns-lookup-bind-address")
- .containsEntry("dnsLookupBindPort", 17)
- .containsEntry("socks5ProxyAddress", "my-socks5-proxy-address")
- .containsEntry("socks5ProxyUsername", "my-socks5-proxy-username")
- .containsEntry("socks5ProxyPassword", "my-socks5-proxy-password");
- }
-
- @Test
- void authenticationUsingAuthParamsString() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.client.auth-plugin-class-name",
- "org.apache.pulsar.client.impl.auth.AuthenticationToken");
- props.put("spring.pulsar.client.auth-params", authParamsStr);
- bind(props);
- assertThat(properties.getClient().getAuthParams()).isEqualTo(authParamsStr);
- assertThat(properties.getClient().getAuthPluginClassName()).isEqualTo(authPluginClassName);
- Map clientProps = properties.buildClientProperties();
-
- assertThat(clientProps).containsEntry("authPluginClassName", authPluginClassName)
- .containsEntry("authParams", authParamsStr);
- }
-
- @Test
- void authenticationUsingAuthenticationMap() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.client.auth-plugin-class-name", authPluginClassName);
- props.put("spring.pulsar.client.authentication.token", authToken);
- bind(props);
- assertThat(properties.getClient().getAuthentication()).containsEntry("token", authToken);
- assertThat(properties.getClient().getAuthPluginClassName()).isEqualTo(authPluginClassName);
- Map clientProps = properties.buildClientProperties();
- assertThat(clientProps).containsEntry("authPluginClassName", authPluginClassName)
- .containsEntry("authParams", authParamsStr);
- }
-
- @Test
- void authenticationNotAllowedUsingBothAuthParamsStringAndAuthenticationMap() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.client.auth-plugin-class-name", authPluginClassName);
- props.put("spring.pulsar.client.auth-params", authParamsStr);
- props.put("spring.pulsar.client.authentication.token", authToken);
- bind(props);
- assertThatIllegalArgumentException().isThrownBy(properties::buildClientProperties).withMessageContaining(
- "Cannot set both spring.pulsar.client.authParams and spring.pulsar.client.authentication.*");
- }
-
- }
-
- @Nested
- class AdminPropertiesTests {
-
- private final String authPluginClassName = "org.apache.pulsar.client.impl.auth.AuthenticationToken";
-
- private final String authParamsStr = "{\"token\":\"1234\"}";
-
- private final String authToken = "1234";
-
- @Test
- void adminProperties() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.administration.service-url", "my-service-url");
- props.put("spring.pulsar.administration.connection-timeout", "12s");
- props.put("spring.pulsar.administration.read-timeout", "13s");
- props.put("spring.pulsar.administration.request-timeout", "14s");
- props.put("spring.pulsar.administration.auto-cert-refresh-time", "15s");
- props.put("spring.pulsar.administration.tls-hostname-verification-enable", "true");
- props.put("spring.pulsar.administration.tls-trust-certs-file-path", "my-trust-certs-file-path");
- props.put("spring.pulsar.administration.tls-allow-insecure-connection", "true");
- props.put("spring.pulsar.administration.use-key-store-tls", "true");
- props.put("spring.pulsar.administration.ssl-provider", "my-ssl-provider");
- props.put("spring.pulsar.administration.tls-trust-store-type", "my-trust-store-type");
- props.put("spring.pulsar.administration.tls-trust-store-path", "my-trust-store-path");
- props.put("spring.pulsar.administration.tls-trust-store-password", "my-trust-store-password");
- props.put("spring.pulsar.administration.tls-ciphers[0]", "my-tls-cipher");
- props.put("spring.pulsar.administration.tls-protocols[0]", "my-tls-protocol");
-
- bind(props);
- Map adminProps = properties.buildAdminProperties();
-
- // Verify that the props can NOT be loaded directly via a ClientBuilder due to
- // the
- // unknown readTimeout and autoCertRefreshTime properties
- assertThatRuntimeException().isThrownBy(() -> PulsarAdmin.builder().loadConf(adminProps)).havingCause()
- .withMessageContaining("Unrecognized field \"autoCertRefreshSeconds\"");
-
- assertThat(adminProps).containsEntry("serviceUrl", "my-service-url")
- .containsEntry("connectionTimeoutMs", 12_000).containsEntry("readTimeoutMs", 13_000)
- .containsEntry("requestTimeoutMs", 14_000).containsEntry("autoCertRefreshSeconds", 15)
- .containsEntry("tlsHostnameVerificationEnable", true)
- .containsEntry("tlsTrustCertsFilePath", "my-trust-certs-file-path")
- .containsEntry("tlsAllowInsecureConnection", true).containsEntry("useKeyStoreTls", true)
- .containsEntry("sslProvider", "my-ssl-provider")
- .containsEntry("tlsTrustStoreType", "my-trust-store-type")
- .containsEntry("tlsTrustStorePath", "my-trust-store-path")
- .containsEntry("tlsTrustStorePassword", "my-trust-store-password")
- .hasEntrySatisfying("tlsCiphers",
- ciphers -> assertThat(ciphers)
- .asInstanceOf(InstanceOfAssertFactories.collection(String.class))
- .containsExactly("my-tls-cipher"))
- .hasEntrySatisfying("tlsProtocols",
- protocols -> assertThat(protocols)
- .asInstanceOf(InstanceOfAssertFactories.collection(String.class))
- .containsExactly("my-tls-protocol"));
- }
-
- @Test
- void authenticationUsingAuthParamsString() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.administration.auth-plugin-class-name",
- "org.apache.pulsar.client.impl.auth.AuthenticationToken");
- props.put("spring.pulsar.administration.auth-params", authParamsStr);
- bind(props);
- assertThat(properties.getAdministration().getAuthParams()).isEqualTo(authParamsStr);
- assertThat(properties.getAdministration().getAuthPluginClassName()).isEqualTo(authPluginClassName);
- Map adminProps = properties.buildAdminProperties();
- assertThat(adminProps).containsEntry("authPluginClassName", authPluginClassName).containsEntry("authParams",
- authParamsStr);
- }
-
- @Test
- void authenticationUsingAuthenticationMap() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.administration.auth-plugin-class-name", authPluginClassName);
- props.put("spring.pulsar.administration.authentication.token", authToken);
- bind(props);
- assertThat(properties.getAdministration().getAuthentication()).containsEntry("token", authToken);
- assertThat(properties.getAdministration().getAuthPluginClassName()).isEqualTo(authPluginClassName);
- Map adminProps = properties.buildAdminProperties();
- assertThat(adminProps).containsEntry("authPluginClassName", authPluginClassName).containsEntry("authParams",
- authParamsStr);
- }
-
- @Test
- void authenticationNotAllowedUsingBothAuthParamsStringAndAuthenticationMap() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.administration.auth-plugin-class-name", authPluginClassName);
- props.put("spring.pulsar.administration.auth-params", authParamsStr);
- props.put("spring.pulsar.administration.authentication.token", authToken);
- bind(props);
- assertThatIllegalArgumentException().isThrownBy(properties::buildAdminProperties).withMessageContaining(
- "Cannot set both spring.pulsar.administration.authParams and spring.pulsar.administration.authentication.*");
- }
-
- }
-
- @Nested
- class DefaultsTypeMappingsPropertiesTests {
-
- @Test
- void emptyByDefault() {
- assertThat(properties.getDefaults().getTypeMappings()).isEmpty();
- }
-
- @Test
- void withTopicsOnly() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.defaults.type-mappings[0].message-type", Foo.class.getName());
- props.put("spring.pulsar.defaults.type-mappings[0].topic-name", "foo-topic");
- props.put("spring.pulsar.defaults.type-mappings[1].message-type", String.class.getName());
- props.put("spring.pulsar.defaults.type-mappings[1].topic-name", "string-topic");
- bind(props);
- assertThat(properties.getDefaults().getTypeMappings()).containsExactly(
- new TypeMapping(Foo.class, "foo-topic", null), new TypeMapping(String.class, "string-topic", null));
- }
-
- @Test
- void withSchemaOnly() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.defaults.type-mappings[0].message-type", Foo.class.getName());
- props.put("spring.pulsar.defaults.type-mappings[0].schema-info.schema-type", "JSON");
- bind(props);
- assertThat(properties.getDefaults().getTypeMappings())
- .containsExactly(new TypeMapping(Foo.class, null, new SchemaInfo(SchemaType.JSON, null)));
- }
-
- @Test
- void withTopicAndSchema() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.defaults.type-mappings[0].message-type", Foo.class.getName());
- props.put("spring.pulsar.defaults.type-mappings[0].topic-name", "foo-topic");
- props.put("spring.pulsar.defaults.type-mappings[0].schema-info.schema-type", "JSON");
- bind(props);
- assertThat(properties.getDefaults().getTypeMappings())
- .containsExactly(new TypeMapping(Foo.class, "foo-topic", new SchemaInfo(SchemaType.JSON, null)));
- }
-
- @Test
- void withKeyValueSchema() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.defaults.type-mappings[0].message-type", Foo.class.getName());
- props.put("spring.pulsar.defaults.type-mappings[0].schema-info.schema-type", "KEY_VALUE");
- props.put("spring.pulsar.defaults.type-mappings[0].schema-info.message-key-type", String.class.getName());
- bind(props);
- assertThat(properties.getDefaults().getTypeMappings()).containsExactly(
- new TypeMapping(Foo.class, null, new SchemaInfo(SchemaType.KEY_VALUE, String.class)));
- }
-
- @Test
- void schemaTypeRequired() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.defaults.type-mappings[0].message-type", Foo.class.getName());
- props.put("spring.pulsar.defaults.type-mappings[0].schema-info.message-key-type", String.class.getName());
- assertThatExceptionOfType(BindException.class).isThrownBy(() -> bind(props)).havingRootCause()
- .withMessageContaining("schemaType must not be null");
- }
-
- @Test
- void schemaTypeNoneNotAllowed() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.defaults.type-mappings[0].message-type", Foo.class.getName());
- props.put("spring.pulsar.defaults.type-mappings[0].schema-info.schema-type", "NONE");
- assertThatExceptionOfType(BindException.class).isThrownBy(() -> bind(props)).havingRootCause()
- .withMessageContaining("schemaType NONE not supported");
- }
-
- @Test
- void messageKeyTypeOnlyAllowedForKeyValueSchemaType() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.defaults.type-mappings[0].message-type", Foo.class.getName());
- props.put("spring.pulsar.defaults.type-mappings[0].schema-info.schema-type", "JSON");
- props.put("spring.pulsar.defaults.type-mappings[0].schema-info.message-key-type", String.class.getName());
- assertThatExceptionOfType(BindException.class).isThrownBy(() -> bind(props)).havingRootCause()
- .withMessageContaining("messageKeyType can only be set when schemaType is KEY_VALUE");
- }
-
- record Foo(String value) {
- }
-
- }
-
- @Nested
- class ProducerPropertiesTests {
-
- @Test
- void producerProperties() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.producer.topic-name", "my-topic");
- props.put("spring.pulsar.producer.producer-name", "my-producer");
- props.put("spring.pulsar.producer.send-timeout", "2s");
- props.put("spring.pulsar.producer.block-if-queue-full", "true");
- props.put("spring.pulsar.producer.max-pending-messages", "3");
- props.put("spring.pulsar.producer.max-pending-messages-across-partitions", "4");
- props.put("spring.pulsar.producer.message-routing-mode", "custompartition");
- props.put("spring.pulsar.producer.hashing-scheme", "murmur3_32hash");
- props.put("spring.pulsar.producer.crypto-failure-action", "send");
- props.put("spring.pulsar.producer.batching-max-publish-delay", "5s");
- props.put("spring.pulsar.producer.batching-partition-switch-frequency-by-publish-delay", "6");
- props.put("spring.pulsar.producer.batching-max-messages", "7");
- props.put("spring.pulsar.producer.batching-max-bytes", "8");
- props.put("spring.pulsar.producer.batching-enabled", "false");
- props.put("spring.pulsar.producer.chunking-enabled", "true");
- props.put("spring.pulsar.producer.encryption-keys[0]", "my-key");
- props.put("spring.pulsar.producer.compression-type", "lz4");
- props.put("spring.pulsar.producer.initial-sequence-id", "9");
- props.put("spring.pulsar.producer.producer-access-mode", "exclusive");
- props.put("spring.pulsar.producer.lazy-start=partitioned-producers", "true");
- props.put("spring.pulsar.producer.properties[my-prop]", "my-prop-value");
-
- bind(props);
- Map producerProps = properties.buildProducerProperties();
-
- // Verify that the props can be loaded in a ProducerBuilder
- assertThatNoException().isThrownBy(() -> ConfigurationDataUtils.loadData(producerProps,
- new ProducerConfigurationData(), ProducerConfigurationData.class));
-
- assertThat(producerProps).containsEntry("topicName", "my-topic")
- .containsEntry("producerName", "my-producer").containsEntry("sendTimeoutMs", 2_000)
- .containsEntry("blockIfQueueFull", true).containsEntry("maxPendingMessages", 3)
- .containsEntry("maxPendingMessagesAcrossPartitions", 4)
- .containsEntry("messageRoutingMode", MessageRoutingMode.CustomPartition)
- .containsEntry("hashingScheme", HashingScheme.Murmur3_32Hash)
- .containsEntry("cryptoFailureAction", ProducerCryptoFailureAction.SEND)
- .containsEntry("batchingMaxPublishDelayMicros", 5_000_000L)
- .containsEntry("batchingPartitionSwitchFrequencyByPublishDelay", 6)
- .containsEntry("batchingMaxMessages", 7).containsEntry("batchingMaxBytes", 8)
- .containsEntry("batchingEnabled", false).containsEntry("chunkingEnabled", true)
- .hasEntrySatisfying("encryptionKeys",
- keys -> assertThat(keys).asInstanceOf(InstanceOfAssertFactories.collection(String.class))
- .containsExactly("my-key"))
- .containsEntry("compressionType", CompressionType.LZ4).containsEntry("initialSequenceId", 9L)
- .containsEntry("accessMode", ProducerAccessMode.Exclusive)
- .containsEntry("lazyStartPartitionedProducers", true).hasEntrySatisfying("properties",
- properties -> assertThat(properties)
- .asInstanceOf(InstanceOfAssertFactories.map(String.class, String.class))
- .containsEntry("my-prop", "my-prop-value"));
- }
-
- }
-
- @Nested
- class ConsumerPropertiesTests {
-
- @Test
- void consumerProperties() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.consumer.topics[0]", "my-topic");
- props.put("spring.pulsar.consumer.topics-pattern", "my-pattern");
- props.put("spring.pulsar.consumer.subscription-name", "my-subscription");
- props.put("spring.pulsar.consumer.subscription-type", "shared");
- props.put("spring.pulsar.consumer.subscription-properties[my-sub-prop]", "my-sub-prop-value");
- props.put("spring.pulsar.consumer.subscription-mode", "nondurable");
- props.put("spring.pulsar.consumer.receiver-queue-size", "1");
- props.put("spring.pulsar.consumer.acknowledgements-group-time", "2s");
- props.put("spring.pulsar.consumer.negative-ack-redelivery-delay", "3s");
- props.put("spring.pulsar.consumer.max-total-receiver-queue-size-across-partitions", "5");
- props.put("spring.pulsar.consumer.consumer-name", "my-consumer");
- props.put("spring.pulsar.consumer.ack-timeout", "6s");
- props.put("spring.pulsar.consumer.tick-duration", "7s");
- props.put("spring.pulsar.consumer.priority-level", "8");
- props.put("spring.pulsar.consumer.crypto-failure-action", "discard");
- props.put("spring.pulsar.consumer.properties[my-prop]", "my-prop-value");
- props.put("spring.pulsar.consumer.read-compacted", "true");
- props.put("spring.pulsar.consumer.subscription-initial-position", "earliest");
- props.put("spring.pulsar.consumer.pattern-auto-discovery-period", "9");
- props.put("spring.pulsar.consumer.regex-subscription-mode", "all-topics");
- props.put("spring.pulsar.consumer.dead-letter-policy.max-redeliver-count", "4");
- props.put("spring.pulsar.consumer.dead-letter-policy.retry-letter-topic", "my-retry-topic");
- props.put("spring.pulsar.consumer.dead-letter-policy.dead-letter-topic", "my-dlt-topic");
- props.put("spring.pulsar.consumer.dead-letter-policy.initial-subscription-name", "my-initial-subscription");
- props.put("spring.pulsar.consumer.retry-enable", "true");
- props.put("spring.pulsar.consumer.auto-update-partitions", "false");
- props.put("spring.pulsar.consumer.auto-update-partitions-interval", "10s");
- props.put("spring.pulsar.consumer.replicate-subscription-state", "true");
- props.put("spring.pulsar.consumer.reset-include-head", "true");
- props.put("spring.pulsar.consumer.batch-index-ack-enabled", "true");
- props.put("spring.pulsar.consumer.ack-receipt-enabled", "true");
- props.put("spring.pulsar.consumer.pool-messages", "true");
- props.put("spring.pulsar.consumer.start-paused", "true");
- props.put("spring.pulsar.consumer.auto-ack-oldest-chunked-message-on-queue-full", "false");
- props.put("spring.pulsar.consumer.max-pending-chunked-message", "11");
- props.put("spring.pulsar.consumer.expire-time-of-incomplete-chunked-message", "12s");
-
- bind(props);
- Map consumerProps = properties.buildConsumerProperties();
-
- // Verify that the props can be loaded in a ConsumerBuilder
- assertThatNoException().isThrownBy(() -> ConfigurationDataUtils.loadData(consumerProps,
- new ConsumerConfigurationData<>(), ConsumerConfigurationData.class));
-
- assertThat(consumerProps)
- .hasEntrySatisfying("topicNames",
- topics -> assertThat(topics)
- .asInstanceOf(InstanceOfAssertFactories.collection(String.class))
- .containsExactly("my-topic"))
- .hasEntrySatisfying("topicsPattern", p -> assertThat(p.toString()).isEqualTo("my-pattern"))
- .containsEntry("subscriptionName", "my-subscription")
- .containsEntry("subscriptionType", SubscriptionType.Shared)
- .hasEntrySatisfying("subscriptionProperties",
- properties -> assertThat(properties)
- .asInstanceOf(InstanceOfAssertFactories.map(String.class, String.class))
- .containsEntry("my-sub-prop", "my-sub-prop-value"))
- .containsEntry("subscriptionMode", SubscriptionMode.NonDurable)
- .containsEntry("receiverQueueSize", 1).containsEntry("acknowledgementsGroupTimeMicros", 2_000_000L)
- .containsEntry("negativeAckRedeliveryDelayMicros", 3_000_000L)
- .containsEntry("maxTotalReceiverQueueSizeAcrossPartitions", 5)
- .containsEntry("consumerName", "my-consumer").containsEntry("ackTimeoutMillis", 6_000L)
- .containsEntry("tickDurationMillis", 7_000L).containsEntry("priorityLevel", 8)
- .containsEntry("cryptoFailureAction", ConsumerCryptoFailureAction.DISCARD)
- .hasEntrySatisfying("properties",
- properties -> assertThat(properties)
- .asInstanceOf(InstanceOfAssertFactories.map(String.class, String.class))
- .containsEntry("my-prop", "my-prop-value"))
- .containsEntry("readCompacted", true)
- .containsEntry("subscriptionInitialPosition", SubscriptionInitialPosition.Earliest)
- .containsEntry("patternAutoDiscoveryPeriod", 9)
- .containsEntry("regexSubscriptionMode", RegexSubscriptionMode.AllTopics)
- .hasEntrySatisfying("deadLetterPolicy", dlp -> {
- DeadLetterPolicy deadLetterPolicy = (DeadLetterPolicy) dlp;
- assertThat(deadLetterPolicy.getMaxRedeliverCount()).isEqualTo(4);
- assertThat(deadLetterPolicy.getRetryLetterTopic()).isEqualTo("my-retry-topic");
- assertThat(deadLetterPolicy.getDeadLetterTopic()).isEqualTo("my-dlt-topic");
- assertThat(deadLetterPolicy.getInitialSubscriptionName()).isEqualTo("my-initial-subscription");
- }).containsEntry("retryEnable", true).containsEntry("autoUpdatePartitions", false)
- .containsEntry("autoUpdatePartitionsIntervalSeconds", 10L)
- .containsEntry("replicateSubscriptionState", true).containsEntry("resetIncludeHead", true)
- .containsEntry("batchIndexAckEnabled", true).containsEntry("ackReceiptEnabled", true)
- .containsEntry("poolMessages", true).containsEntry("startPaused", true)
- .containsEntry("autoAckOldestChunkedMessageOnQueueFull", false)
- .containsEntry("maxPendingChunkedMessage", 11)
- .containsEntry("expireTimeOfIncompleteChunkedMessageMillis", 12_000L);
- }
-
- }
-
- @Nested
- class FunctionPropertiesTests {
-
- @Test
- void functionProperties() {
- Map props = new HashMap<>();
- bind(props);
-
- // check defaults
- assertThat(properties.getFunction().getFailFast()).isTrue();
- assertThat(properties.getFunction().getPropagateFailures()).isTrue();
- assertThat(properties.getFunction().getPropagateStopFailures()).isFalse();
-
- // set values and verify
- props.put("spring.pulsar.function.fail-fast", "false");
- props.put("spring.pulsar.function.propagate-failures", "false");
- props.put("spring.pulsar.function.propagate-stop-failures", "true");
- bind(props);
-
- assertThat(properties.getFunction().getFailFast()).isFalse();
- assertThat(properties.getFunction().getPropagateFailures()).isFalse();
- assertThat(properties.getFunction().getPropagateStopFailures()).isTrue();
- }
-
- }
-
- @Nested
- class ReaderPropertiesTests {
-
- @Test
- void readerProperties() {
- Map props = new HashMap<>();
-
- props.put("spring.pulsar.reader.topic-names", "my-topic");
- props.put("spring.pulsar.reader.receiver-queue-size", "100");
- props.put("spring.pulsar.reader.reader-name", "my-reader");
- props.put("spring.pulsar.reader.subscription-name", "my-subscription");
- props.put("spring.pulsar.reader.subscription-role-prefix", "sub-role");
- props.put("spring.pulsar.reader.read-compacted", "true");
- props.put("spring.pulsar.reader.reset-include-head", "true");
- bind(props);
-
- Map readerProps = properties.buildReaderProperties();
-
- // Verify that the props can be loaded in a ReaderBuilder
- assertThatNoException().isThrownBy(() -> ConfigurationDataUtils.loadData(readerProps,
- new ReaderConfigurationData<>(), ReaderConfigurationData.class));
-
- assertThat(readerProps)
- .hasEntrySatisfying("topicNames",
- topics -> assertThat(topics).asInstanceOf(InstanceOfAssertFactories.list(String.class))
- .containsExactly("my-topic"))
- .containsEntry("receiverQueueSize", 100).containsEntry("readerName", "my-reader")
- .containsEntry("subscriptionName", "my-subscription")
- .containsEntry("subscriptionRolePrefix", "sub-role").containsEntry("readCompacted", true)
- .containsEntry("resetIncludeHead", true);
- }
-
- }
-
-}
diff --git a/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/PulsarReactiveAutoConfigurationTests.java b/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/PulsarReactiveAutoConfigurationTests.java
deleted file mode 100644
index d1416a6c..00000000
--- a/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/PulsarReactiveAutoConfigurationTests.java
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright 2022-2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.autoconfigure;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-
-import java.time.Duration;
-import java.util.Collections;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Supplier;
-
-import org.apache.pulsar.client.api.PulsarClient;
-import org.apache.pulsar.client.api.SubscriptionType;
-import org.apache.pulsar.common.schema.SchemaType;
-import org.apache.pulsar.reactive.client.adapter.AdaptedReactivePulsarClientFactory;
-import org.apache.pulsar.reactive.client.adapter.ProducerCacheProvider;
-import org.apache.pulsar.reactive.client.api.ReactiveMessageConsumerSpec;
-import org.apache.pulsar.reactive.client.api.ReactiveMessageReaderSpec;
-import org.apache.pulsar.reactive.client.api.ReactiveMessageSenderCache;
-import org.apache.pulsar.reactive.client.api.ReactiveMessageSenderSpec;
-import org.apache.pulsar.reactive.client.api.ReactivePulsarClient;
-import org.apache.pulsar.reactive.client.producercache.CaffeineProducerCacheProvider;
-import org.assertj.core.api.AbstractObjectAssert;
-import org.assertj.core.api.InstanceOfAssertFactories;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.ValueSource;
-import org.mockito.MockedStatic;
-import org.mockito.Mockito;
-
-import org.springframework.boot.autoconfigure.AutoConfigurations;
-import org.springframework.boot.test.context.FilteredClassLoader;
-import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
-import org.springframework.boot.test.context.runner.ApplicationContextRunner;
-import org.springframework.pulsar.config.PulsarClientFactoryBean;
-import org.springframework.pulsar.core.SchemaResolver;
-import org.springframework.pulsar.core.TopicResolver;
-import org.springframework.pulsar.reactive.config.DefaultReactivePulsarListenerContainerFactory;
-import org.springframework.pulsar.reactive.config.ReactivePulsarListenerContainerFactory;
-import org.springframework.pulsar.reactive.config.ReactivePulsarListenerEndpointRegistry;
-import org.springframework.pulsar.reactive.config.annotation.EnableReactivePulsar;
-import org.springframework.pulsar.reactive.config.annotation.ReactivePulsarBootstrapConfiguration;
-import org.springframework.pulsar.reactive.config.annotation.ReactivePulsarListenerAnnotationBeanPostProcessor;
-import org.springframework.pulsar.reactive.core.DefaultReactivePulsarConsumerFactory;
-import org.springframework.pulsar.reactive.core.DefaultReactivePulsarReaderFactory;
-import org.springframework.pulsar.reactive.core.DefaultReactivePulsarSenderFactory;
-import org.springframework.pulsar.reactive.core.ReactivePulsarConsumerFactory;
-import org.springframework.pulsar.reactive.core.ReactivePulsarReaderFactory;
-import org.springframework.pulsar.reactive.core.ReactivePulsarSenderFactory;
-import org.springframework.pulsar.reactive.core.ReactivePulsarTemplate;
-import org.springframework.pulsar.reactive.listener.ReactivePulsarContainerProperties;
-
-/**
- * Autoconfiguration tests for {@link PulsarReactiveAutoConfiguration}.
- *
- * @author Christophe Bornet
- * @author Chris Bono
- */
-@SuppressWarnings("unchecked")
-class PulsarReactiveAutoConfigurationTests {
-
- private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
- .withConfiguration(AutoConfigurations.of(PulsarAutoConfiguration.class))
- .withConfiguration(AutoConfigurations.of(PulsarReactiveAutoConfiguration.class));
-
- @Test
- void autoConfigurationSkippedWhenReactivePulsarClientNotOnClasspath() {
- this.contextRunner.withClassLoader(new FilteredClassLoader(ReactivePulsarClient.class)).run(
- (context) -> assertThat(context).hasNotFailed().doesNotHaveBean(PulsarReactiveAutoConfiguration.class));
- }
-
- @Test
- void autoConfigurationSkippedWhenReactivePulsarTemplateNotOnClasspath() {
- this.contextRunner.withClassLoader(new FilteredClassLoader(ReactivePulsarTemplate.class)).run(
- (context) -> assertThat(context).hasNotFailed().doesNotHaveBean(PulsarReactiveAutoConfiguration.class));
- }
-
- @Test
- void annotationDrivenConfigurationSkippedWhenEnablePulsarAnnotationNotOnClasspath() {
- this.contextRunner.withClassLoader(new FilteredClassLoader(EnableReactivePulsar.class))
- .run((context) -> assertThat(context).hasNotFailed()
- .doesNotHaveBean(PulsarReactiveAnnotationDrivenConfiguration.class));
- }
-
- @Test
- void bootstrapConfigurationSkippedWhenCustomReactivePulsarListenerAnnotationProcessorDefined() {
- this.contextRunner
- .withBean("org.springframework.pulsar.config.internalReactivePulsarListenerAnnotationProcessor",
- String.class, () -> "someFauxBean")
- .run((context) -> assertThat(context).hasNotFailed()
- .doesNotHaveBean(ReactivePulsarBootstrapConfiguration.class));
- }
-
- @Test
- void defaultBeansAreAutoConfigured() {
- this.contextRunner.run((context) -> assertThat(context).hasNotFailed()
- .hasSingleBean(ReactivePulsarTemplate.class).hasSingleBean(ReactivePulsarClient.class)
- .hasSingleBean(ProducerCacheProvider.class).hasSingleBean(ReactiveMessageSenderCache.class)
- .hasSingleBean(ReactivePulsarSenderFactory.class).hasSingleBean(ReactivePulsarTemplate.class)
- .hasSingleBean(DefaultReactivePulsarListenerContainerFactory.class)
- .hasSingleBean(ReactivePulsarListenerAnnotationBeanPostProcessor.class)
- .hasSingleBean(ReactivePulsarListenerEndpointRegistry.class));
- }
-
- @ParameterizedTest
- @ValueSource(classes = { ReactivePulsarClient.class, ProducerCacheProvider.class, ReactiveMessageSenderCache.class,
- ReactivePulsarSenderFactory.class, ReactivePulsarConsumerFactory.class, ReactivePulsarReaderFactory.class,
- ReactivePulsarTemplate.class })
- void customBeanIsRespected(Class beanClass) {
- T bean = mock(beanClass);
- this.contextRunner.withBean(beanClass.getName(), beanClass, () -> bean)
- .run((context) -> assertThat(context).hasNotFailed().getBean(beanClass).isSameAs(bean));
- }
-
- @SuppressWarnings("rawtypes")
- @Test
- void beansAreInjectedInReactivePulsarListenerContainerFactory() {
- ReactivePulsarConsumerFactory> consumerFactory = mock(ReactivePulsarConsumerFactory.class);
- SchemaResolver schemaResolver = mock(SchemaResolver.class);
- this.contextRunner
- .withBean("customReactivePulsarConsumerFactory", ReactivePulsarConsumerFactory.class,
- () -> consumerFactory)
- .withBean("schemaResolver", SchemaResolver.class, () -> schemaResolver).run((context -> {
- AbstractObjectAssert extends AbstractObjectAssert, DefaultReactivePulsarListenerContainerFactory>, DefaultReactivePulsarListenerContainerFactory> containerFactory = assertThat(
- context).hasNotFailed().getBean(DefaultReactivePulsarListenerContainerFactory.class);
- containerFactory.extracting("consumerFactory").isSameAs(consumerFactory);
- containerFactory.extracting(DefaultReactivePulsarListenerContainerFactory::getContainerProperties)
- .extracting(ReactivePulsarContainerProperties::getSchemaResolver).isSameAs(schemaResolver);
- }));
- }
-
- @Test
- void customReactivePulsarListenerContainerFactoryIsRespected() {
- ReactivePulsarListenerContainerFactory listenerContainerFactory = mock(
- ReactivePulsarListenerContainerFactory.class);
- this.contextRunner
- .withBean("reactivePulsarListenerContainerFactory", ReactivePulsarListenerContainerFactory.class,
- () -> listenerContainerFactory)
- .run((context) -> assertThat(context).hasNotFailed()
- .getBean(ReactivePulsarListenerContainerFactory.class).isSameAs(listenerContainerFactory));
- }
-
- @Test
- void customReactivePulsarListenerAnnotationBeanPostProcessorIsRespected() {
- ReactivePulsarListenerAnnotationBeanPostProcessor listenerAnnotationBeanPostProcessor = mock(
- ReactivePulsarListenerAnnotationBeanPostProcessor.class);
- this.contextRunner
- .withBean("org.springframework.pulsar.config.internalReactivePulsarListenerAnnotationProcessor",
- ReactivePulsarListenerAnnotationBeanPostProcessor.class,
- () -> listenerAnnotationBeanPostProcessor)
- .run((context) -> assertThat(context).hasNotFailed()
- .getBean(ReactivePulsarListenerAnnotationBeanPostProcessor.class)
- .isSameAs(listenerAnnotationBeanPostProcessor));
- }
-
- @Test
- @SuppressWarnings("rawtypes")
- void beansAreInjectedInReactivePulsarTemplate() {
- ReactivePulsarSenderFactory> senderFactory = mock(ReactivePulsarSenderFactory.class);
- SchemaResolver schemaResolver = mock(SchemaResolver.class);
- this.contextRunner
- .withBean("customReactivePulsarSenderFactory", ReactivePulsarSenderFactory.class, () -> senderFactory)
- .withBean("schemaResolver", SchemaResolver.class, () -> schemaResolver).run((context -> {
- AbstractObjectAssert extends AbstractObjectAssert, ReactivePulsarTemplate>, ReactivePulsarTemplate> template = assertThat(
- context).hasNotFailed().getBean(ReactivePulsarTemplate.class);
- template.extracting("reactiveMessageSenderFactory").isSameAs(senderFactory);
- template.extracting("schemaResolver").isSameAs(schemaResolver);
- }));
- }
-
- @Test
- @SuppressWarnings("rawtypes")
- void beansAreInjectedInReactivePulsarSenderFactory() throws Exception {
- ReactivePulsarClient client = mock(ReactivePulsarClient.class);
- try (ReactiveMessageSenderCache cache = mock(ReactiveMessageSenderCache.class)) {
- this.contextRunner.withPropertyValues("spring.pulsar.reactive.sender.topic-name=test-topic")
- .withBean("customReactivePulsarClient", ReactivePulsarClient.class, () -> client)
- .withBean("customReactiveMessageSenderCache", ReactiveMessageSenderCache.class, () -> cache)
- .run((context -> {
- AbstractObjectAssert extends AbstractObjectAssert, DefaultReactivePulsarSenderFactory>, DefaultReactivePulsarSenderFactory> senderFactory = assertThat(
- context).hasNotFailed().getBean(DefaultReactivePulsarSenderFactory.class);
- senderFactory.extracting(DefaultReactivePulsarSenderFactory::getReactiveMessageSenderSpec)
- .extracting(ReactiveMessageSenderSpec::getTopicName).isEqualTo("test-topic");
- senderFactory.extracting("reactivePulsarClient",
- InstanceOfAssertFactories.type(ReactivePulsarClient.class)).isSameAs(client);
- senderFactory
- .extracting("reactiveMessageSenderCache",
- InstanceOfAssertFactories.type(ReactiveMessageSenderCache.class))
- .isSameAs(cache);
- senderFactory.extracting("topicResolver", InstanceOfAssertFactories.type(TopicResolver.class))
- .isSameAs(context.getBean(TopicResolver.class));
-
- }));
- }
- }
-
- @Test
- @SuppressWarnings("rawtypes")
- void beansAreInjectedInReactivePulsarConsumerFactory() {
- ReactivePulsarClient client = mock(ReactivePulsarClient.class);
- this.contextRunner.withPropertyValues("spring.pulsar.reactive.consumer.consumer-name=test-consumer")
- .withBean("customReactivePulsarClient", ReactivePulsarClient.class, () -> client).run((context -> {
- AbstractObjectAssert extends AbstractObjectAssert, DefaultReactivePulsarConsumerFactory>, DefaultReactivePulsarConsumerFactory> senderFactory = assertThat(
- context).hasNotFailed().getBean(DefaultReactivePulsarConsumerFactory.class);
- senderFactory
- .extracting("consumerSpec",
- InstanceOfAssertFactories.type(ReactiveMessageConsumerSpec.class))
- .extracting(ReactiveMessageConsumerSpec::getConsumerName).isEqualTo("test-consumer");
- senderFactory.extracting("reactivePulsarClient",
- InstanceOfAssertFactories.type(ReactivePulsarClient.class)).isSameAs(client);
- }));
-
- }
-
- @Test
- @SuppressWarnings("rawtypes")
- void beansAreInjectedInReactivePulsarReaderFactory() {
- ReactivePulsarClient client = mock(ReactivePulsarClient.class);
- this.contextRunner.withPropertyValues("spring.pulsar.reactive.reader.reader-name=test-reader")
- .withBean("customReactivePulsarClient", ReactivePulsarClient.class, () -> client).run((context -> {
- AbstractObjectAssert extends AbstractObjectAssert, DefaultReactivePulsarReaderFactory>, DefaultReactivePulsarReaderFactory> senderFactory = assertThat(
- context).hasNotFailed().getBean(DefaultReactivePulsarReaderFactory.class);
- senderFactory
- .extracting("readerSpec", InstanceOfAssertFactories.type(ReactiveMessageReaderSpec.class))
- .extracting(ReactiveMessageReaderSpec::getReaderName).isEqualTo("test-reader");
- senderFactory.extracting("reactivePulsarClient",
- InstanceOfAssertFactories.type(ReactivePulsarClient.class)).isSameAs(client);
- }));
- }
-
- @Test
- void beansAreInjectedInReactiveMessageSenderCache() throws Exception {
- try (ProducerCacheProvider provider = mock(ProducerCacheProvider.class)) {
- this.contextRunner.withBean("customProducerCacheProvider", ProducerCacheProvider.class, () -> provider)
- .run((context -> {
- var senderFactory = assertThat(context).hasNotFailed()
- .getBean(ReactiveMessageSenderCache.class);
- senderFactory.extracting("cacheProvider")
- .asInstanceOf(InstanceOfAssertFactories.type(ProducerCacheProvider.class))
- .isSameAs(provider);
- }));
- }
- }
-
- @Test
- @SuppressWarnings("rawtypes")
- void beansAreInjectedInReactivePulsarClient() throws Exception {
- try (PulsarClient client = mock(PulsarClient.class)) {
- PulsarClientFactoryBean factoryBean = new PulsarClientFactoryBean(Collections.emptyMap()) {
- @Override
- protected PulsarClient createInstance() {
- return client;
- }
- };
- this.contextRunner.withBean("customPulsarClient", PulsarClientFactoryBean.class, () -> factoryBean)
- .run((context -> assertThat(context).hasNotFailed().getBean(ReactivePulsarClient.class)
- .extracting("reactivePulsarResourceAdapter")
- .extracting("pulsarClientSupplier", InstanceOfAssertFactories.type(Supplier.class))
- .extracting(Supplier::get).isSameAs(client)));
- }
- }
-
- @Test
- void reactiveListenerPropertiesAreHonored() {
- contextRunner.withPropertyValues("spring.pulsar.reactive.listener.schema-type=avro",
- "spring.pulsar.reactive.listener.handling-timeout=10s",
- "spring.pulsar.reactive.listener.use-key-ordered-processing=true",
- "spring.pulsar.reactive.consumer.subscription-type=shared").run((context -> {
- AbstractObjectAssert, ReactivePulsarContainerProperties>> properties = assertThat(context)
- .hasNotFailed().getBean(DefaultReactivePulsarListenerContainerFactory.class)
- .extracting(DefaultReactivePulsarListenerContainerFactory::getContainerProperties);
- properties.extracting(ReactivePulsarContainerProperties::getSchemaType).isEqualTo(SchemaType.AVRO);
- properties.extracting(ReactivePulsarContainerProperties::getHandlingTimeout)
- .isEqualTo(Duration.ofSeconds(10));
- properties.extracting(ReactivePulsarContainerProperties::isUseKeyOrderedProcessing).isEqualTo(true);
- properties.extracting(ReactivePulsarContainerProperties::getSubscriptionType)
- .isEqualTo(SubscriptionType.Shared);
- }));
- }
-
- @Nested
- class SenderCacheAutoConfigurationTests {
-
- @Test
- void caffeineCacheUsedByDefault() {
- contextRunner.run(this::assertCaffeineProducerCacheProvider);
- }
-
- @Test
- void caffeineCacheCanBeConfigured() {
- contextRunner
- .withPropertyValues("spring.pulsar.reactive.sender.cache.expire-after-access=100s",
- "spring.pulsar.reactive.sender.cache.maximum-size=5150",
- "spring.pulsar.reactive.sender.cache.initial-capacity=200")
- .run((context) -> assertCaffeineProducerCacheProvider(context).extracting("cache")
- .extracting("cache").hasFieldOrPropertyWithValue("maximum", 5150L)
- .hasFieldOrPropertyWithValue("expiresAfterAccessNanos", TimeUnit.SECONDS.toNanos(100)));
- }
-
- @Test
- void defaultClientCacheIsUsedIfCaffeineProducerCacheProviderNotOnClasspath() {
- ReactiveMessageSenderCache cache = AdaptedReactivePulsarClientFactory.createCache();
- try (MockedStatic mockedClientFactory = Mockito
- .mockStatic(AdaptedReactivePulsarClientFactory.class)) {
- mockedClientFactory.when(AdaptedReactivePulsarClientFactory::createCache).thenReturn(cache);
- mockedClientFactory.when(() -> AdaptedReactivePulsarClientFactory.create(any(PulsarClient.class)))
- .thenReturn(mock(ReactivePulsarClient.class));
- contextRunner.withClassLoader(new FilteredClassLoader(CaffeineProducerCacheProvider.class))
- .run((context) -> assertThat(context).hasNotFailed()
- .doesNotHaveBean(ProducerCacheProvider.class)
- .hasSingleBean(ReactiveMessageSenderCache.class)
- .getBean(ReactiveMessageSenderCache.class).isSameAs(cache));
- mockedClientFactory.verify(AdaptedReactivePulsarClientFactory::createCache);
- }
- }
-
- @Test
- void cacheCanBeDisabled() {
- contextRunner.withPropertyValues("spring.pulsar.reactive.sender.cache.enabled=false")
- .run((context -> assertThat(context).hasNotFailed().doesNotHaveBean(ProducerCacheProvider.class)
- .doesNotHaveBean(ReactiveMessageSenderCache.class)));
- }
-
- private AbstractObjectAssert, ProducerCacheProvider> assertCaffeineProducerCacheProvider(
- AssertableApplicationContext context) {
- return assertThat(context).hasNotFailed().hasSingleBean(ProducerCacheProvider.class)
- .hasSingleBean(ReactiveMessageSenderCache.class).getBean(ProducerCacheProvider.class)
- .isExactlyInstanceOf(CaffeineProducerCacheProvider.class);
- }
-
- }
-
-}
diff --git a/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/PulsarReactivePropertiesTests.java b/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/PulsarReactivePropertiesTests.java
deleted file mode 100644
index aa4838fe..00000000
--- a/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/PulsarReactivePropertiesTests.java
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright 2022-2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.autoconfigure;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.time.Duration;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.pulsar.client.api.CompressionType;
-import org.apache.pulsar.client.api.ConsumerCryptoFailureAction;
-import org.apache.pulsar.client.api.HashingScheme;
-import org.apache.pulsar.client.api.MessageRoutingMode;
-import org.apache.pulsar.client.api.ProducerAccessMode;
-import org.apache.pulsar.client.api.ProducerCryptoFailureAction;
-import org.apache.pulsar.client.api.Range;
-import org.apache.pulsar.client.api.RegexSubscriptionMode;
-import org.apache.pulsar.client.api.SubscriptionInitialPosition;
-import org.apache.pulsar.client.api.SubscriptionMode;
-import org.apache.pulsar.client.api.SubscriptionType;
-import org.apache.pulsar.reactive.client.api.ReactiveMessageConsumerSpec;
-import org.apache.pulsar.reactive.client.api.ReactiveMessageReaderSpec;
-import org.apache.pulsar.reactive.client.api.ReactiveMessageSenderSpec;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.params.ParameterizedTest;
-import org.junit.jupiter.params.provider.EnumSource;
-import org.junit.jupiter.params.provider.EnumSource.Mode;
-
-import org.springframework.boot.context.properties.bind.Bindable;
-import org.springframework.boot.context.properties.bind.Binder;
-import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
-import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
-import org.springframework.pulsar.autoconfigure.PulsarReactiveProperties.SchedulerType;
-
-import reactor.core.scheduler.Schedulers;
-
-/**
- * Unit tests for {@link PulsarReactiveProperties}.
- *
- * @author Christophe Bornet
- */
-public class PulsarReactivePropertiesTests {
-
- private final PulsarReactiveProperties properties = new PulsarReactiveProperties();
-
- private void bind(String name, String value) {
- bind(Collections.singletonMap(name, value));
- }
-
- private void bind(Map map) {
- ConfigurationPropertySource source = new MapConfigurationPropertySource(map);
- new Binder(source).bind("spring.pulsar.reactive", Bindable.ofInstance(this.properties));
- }
-
- @Nested
- class SenderPropertiesTests {
-
- @Test
- void senderPropsToSenderSpec() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.reactive.sender.topic-name", "my-topic");
- props.put("spring.pulsar.reactive.sender.producer-name", "my-producer");
- props.put("spring.pulsar.reactive.sender.send-timeout", "2s");
- props.put("spring.pulsar.reactive.sender.max-pending-messages", "3");
- props.put("spring.pulsar.reactive.sender.max-pending-messages-across-partitions", "4");
- props.put("spring.pulsar.reactive.sender.message-routing-mode", "custompartition");
- props.put("spring.pulsar.reactive.sender.hashing-scheme", "murmur3_32hash");
- props.put("spring.pulsar.reactive.sender.crypto-failure-action", "send");
- props.put("spring.pulsar.reactive.sender.batching-max-publish-delay", "5s");
- props.put("spring.pulsar.reactive.sender.round-robin-router-batching-partition-switch-frequency", "6");
- props.put("spring.pulsar.reactive.sender.batching-max-messages", "7");
- props.put("spring.pulsar.reactive.sender.batching-max-bytes", "8");
- props.put("spring.pulsar.reactive.sender.batching-enabled", "false");
- props.put("spring.pulsar.reactive.sender.chunking-enabled", "true");
- props.put("spring.pulsar.reactive.sender.encryption-keys[0]", "my-key");
- props.put("spring.pulsar.reactive.sender.compression-type", "lz4");
- props.put("spring.pulsar.reactive.sender.initial-sequence-id", "9");
- props.put("spring.pulsar.reactive.sender.producer-access-mode", "exclusive");
- props.put("spring.pulsar.reactive.sender.lazy-start=partitioned-producers", "true");
- props.put("spring.pulsar.reactive.sender.properties[my-prop]", "my-prop-value");
-
- bind(props);
- ReactiveMessageSenderSpec senderSpec = properties.buildReactiveMessageSenderSpec();
-
- assertThat(senderSpec.getTopicName()).isEqualTo("my-topic");
- assertThat(senderSpec.getProducerName()).isEqualTo("my-producer");
- assertThat(senderSpec.getSendTimeout()).isEqualTo(Duration.ofSeconds(2));
- assertThat(senderSpec.getMaxPendingMessages()).isEqualTo(3);
- assertThat(senderSpec.getMaxPendingMessagesAcrossPartitions()).isEqualTo(4);
- assertThat(senderSpec.getMessageRoutingMode()).isEqualTo(MessageRoutingMode.CustomPartition);
- assertThat(senderSpec.getHashingScheme()).isEqualTo(HashingScheme.Murmur3_32Hash);
- assertThat(senderSpec.getCryptoFailureAction()).isEqualTo(ProducerCryptoFailureAction.SEND);
- assertThat(senderSpec.getBatchingMaxPublishDelay()).isEqualTo(Duration.ofSeconds(5));
- assertThat(senderSpec.getRoundRobinRouterBatchingPartitionSwitchFrequency()).isEqualTo(6);
- assertThat(senderSpec.getBatchingMaxMessages()).isEqualTo(7);
- assertThat(senderSpec.getBatchingMaxBytes()).isEqualTo(8);
- assertThat(senderSpec.getBatchingEnabled()).isEqualTo(false);
- assertThat(senderSpec.getChunkingEnabled()).isEqualTo(true);
- assertThat(senderSpec.getEncryptionKeys()).containsExactly("my-key");
- assertThat(senderSpec.getCompressionType()).isEqualTo(CompressionType.LZ4);
- assertThat(senderSpec.getInitialSequenceId()).isEqualTo(9);
- assertThat(senderSpec.getAccessMode()).isEqualTo(ProducerAccessMode.Exclusive);
- assertThat(senderSpec.getLazyStartPartitionedProducers()).isTrue();
- assertThat(senderSpec.getProperties()).hasSize(1).containsEntry("my-prop", "my-prop-value");
- }
-
- }
-
- @Nested
- class ConsumerPropertiesTests {
-
- @Test
- void consumerPropsToConsumerSpec() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.reactive.consumer.topics[0]", "my-topic");
- props.put("spring.pulsar.reactive.consumer.topics-pattern", "my-pattern");
- props.put("spring.pulsar.reactive.consumer.subscription-name", "my-subscription");
- props.put("spring.pulsar.reactive.consumer.subscription-type", "shared");
- props.put("spring.pulsar.reactive.consumer.subscription-mode", "nondurable");
- props.put("spring.pulsar.reactive.consumer.subscription-properties[my-sub-prop]", "my-sub-prop-value");
- props.put("spring.pulsar.reactive.consumer.receiver-queue-size", "1");
- props.put("spring.pulsar.reactive.consumer.acknowledgements-group-time", "2s");
- props.put("spring.pulsar.reactive.consumer.acknowledge-asynchronously", "false");
- props.put("spring.pulsar.reactive.consumer.negative-ack-redelivery-delay", "3s");
- props.put("spring.pulsar.reactive.consumer.dead-letter-policy.max-redeliver-count", "4");
- props.put("spring.pulsar.reactive.consumer.dead-letter-policy.retry-letter-topic", "my-retry-topic");
- props.put("spring.pulsar.reactive.consumer.dead-letter-policy.dead-letter-topic", "my-dlt-topic");
- props.put("spring.pulsar.reactive.consumer.dead-letter-policy.initial-subscription-name",
- "my-initial-subscription");
- props.put("spring.pulsar.reactive.consumer.max-total-receiver-queue-size-across-partitions", "5");
- props.put("spring.pulsar.reactive.consumer.consumer-name", "my-consumer");
- props.put("spring.pulsar.reactive.consumer.ack-timeout", "6s");
- props.put("spring.pulsar.reactive.consumer.ack-timeout-tick-time", "7s");
- props.put("spring.pulsar.reactive.consumer.priority-level", "8");
- props.put("spring.pulsar.reactive.consumer.crypto-failure-action", "discard");
- props.put("spring.pulsar.reactive.consumer.properties[my-prop]", "my-prop-value");
- props.put("spring.pulsar.reactive.consumer.read-compacted", "true");
- props.put("spring.pulsar.reactive.consumer.batch-index-ack-enabled", "true");
- props.put("spring.pulsar.reactive.consumer.subscription-initial-position", "earliest");
- props.put("spring.pulsar.reactive.consumer.topics-pattern-auto-discovery-period", "9s");
- props.put("spring.pulsar.reactive.consumer.topics-pattern-subscription-mode", "alltopics");
- props.put("spring.pulsar.reactive.consumer.auto-update-partitions", "false");
- props.put("spring.pulsar.reactive.consumer.auto-update-partitions-interval", "10s");
- props.put("spring.pulsar.reactive.consumer.replicate-subscription-state", "true");
- props.put("spring.pulsar.reactive.consumer.auto-ack-oldest-chunked-message-on-queue-full", "false");
- props.put("spring.pulsar.reactive.consumer.max-pending-chunked-message", "11");
- props.put("spring.pulsar.reactive.consumer.expire-time-of-incomplete-chunked-message", "12s");
-
- bind(props);
- ReactiveMessageConsumerSpec consumerSpec = properties.buildReactiveMessageConsumerSpec();
-
- assertThat(consumerSpec.getTopicNames()).containsExactly("my-topic");
- assertThat(consumerSpec.getTopicsPattern().toString()).isEqualTo("my-pattern");
- assertThat(consumerSpec.getSubscriptionName()).isEqualTo("my-subscription");
- assertThat(consumerSpec.getSubscriptionType()).isEqualTo(SubscriptionType.Shared);
- assertThat(consumerSpec.getSubscriptionMode()).isEqualTo(SubscriptionMode.NonDurable);
- assertThat(consumerSpec.getSubscriptionProperties()).hasSize(1).containsEntry("my-sub-prop",
- "my-sub-prop-value");
- assertThat(consumerSpec.getReceiverQueueSize()).isEqualTo(1);
- assertThat(consumerSpec.getAcknowledgementsGroupTime()).isEqualTo(Duration.ofSeconds(2));
- assertThat(consumerSpec.getAcknowledgeAsynchronously()).isFalse();
- assertThat(consumerSpec.getNegativeAckRedeliveryDelay()).isEqualTo(Duration.ofSeconds(3));
- assertThat(consumerSpec.getDeadLetterPolicy().getMaxRedeliverCount()).isEqualTo(4);
- assertThat(consumerSpec.getDeadLetterPolicy().getRetryLetterTopic()).isEqualTo("my-retry-topic");
- assertThat(consumerSpec.getDeadLetterPolicy().getDeadLetterTopic()).isEqualTo("my-dlt-topic");
- assertThat(consumerSpec.getDeadLetterPolicy().getInitialSubscriptionName())
- .isEqualTo("my-initial-subscription");
- assertThat(consumerSpec.getMaxTotalReceiverQueueSizeAcrossPartitions()).isEqualTo(5);
- assertThat(consumerSpec.getConsumerName()).isEqualTo("my-consumer");
- assertThat(consumerSpec.getAckTimeout()).isEqualTo(Duration.ofSeconds(6));
- assertThat(consumerSpec.getAckTimeoutTickTime()).isEqualTo(Duration.ofSeconds(7));
- assertThat(consumerSpec.getPriorityLevel()).isEqualTo(8);
- assertThat(consumerSpec.getCryptoFailureAction()).isEqualTo(ConsumerCryptoFailureAction.DISCARD);
- assertThat(consumerSpec.getProperties()).hasSize(1).containsEntry("my-prop", "my-prop-value");
- assertThat(consumerSpec.getReadCompacted()).isTrue();
- assertThat(consumerSpec.getBatchIndexAckEnabled()).isTrue();
- assertThat(consumerSpec.getSubscriptionInitialPosition()).isEqualTo(SubscriptionInitialPosition.Earliest);
- assertThat(consumerSpec.getTopicsPatternAutoDiscoveryPeriod()).isEqualTo(Duration.ofSeconds(9));
- assertThat(consumerSpec.getTopicsPatternSubscriptionMode()).isEqualTo(RegexSubscriptionMode.AllTopics);
- assertThat(consumerSpec.getAutoUpdatePartitions()).isFalse();
- assertThat(consumerSpec.getAutoUpdatePartitionsInterval()).isEqualTo(Duration.ofSeconds(10));
- assertThat(consumerSpec.getReplicateSubscriptionState()).isTrue();
- assertThat(consumerSpec.getAutoAckOldestChunkedMessageOnQueueFull()).isFalse();
- assertThat(consumerSpec.getMaxPendingChunkedMessage()).isEqualTo(11);
- assertThat(consumerSpec.getExpireTimeOfIncompleteChunkedMessage()).isEqualTo(Duration.ofSeconds(12));
- }
-
- @ParameterizedTest
- @EnumSource(value = SchedulerType.class, names = "immediate", mode = Mode.EXCLUDE)
- void acknowledgeScheduler(SchedulerType acknowledgeSchedulerType) {
- bind("spring.pulsar.reactive.consumer.acknowledge-scheduler-type", acknowledgeSchedulerType.name());
- ReactiveMessageConsumerSpec consumerSpec = properties.buildReactiveMessageConsumerSpec();
-
- assertThat(consumerSpec.getAcknowledgeScheduler().toString())
- .isEqualTo("Schedulers.%s()".formatted(acknowledgeSchedulerType));
- }
-
- @Test
- void acknowledgeSchedulerImmediate() {
- bind("spring.pulsar.reactive.consumer.acknowledge-scheduler-type", "immediate");
- ReactiveMessageConsumerSpec consumerSpec = properties.buildReactiveMessageConsumerSpec();
-
- assertThat(consumerSpec.getAcknowledgeScheduler()).isSameAs(Schedulers.immediate());
- }
-
- }
-
- @Nested
- class ReaderPropertiesTests {
-
- @Test
- void readerPropsToReaderSpec() {
- Map props = new HashMap<>();
- props.put("spring.pulsar.reactive.reader.topic-names[0]", "my-topic");
- props.put("spring.pulsar.reactive.reader.reader-name", "my-reader");
- props.put("spring.pulsar.reactive.reader.subscription-name", "my-subscription");
- props.put("spring.pulsar.reactive.reader.generated-subscription-name-prefix", "my-prefix");
- props.put("spring.pulsar.reactive.reader.receiver-queue-size", "1");
- props.put("spring.pulsar.reactive.reader.read-compacted", "true");
- props.put("spring.pulsar.reactive.reader.key-hash-ranges[0].start", "2");
- props.put("spring.pulsar.reactive.reader.key-hash-ranges[0].end", "3");
- props.put("spring.pulsar.reactive.reader.crypto-failure-action", "discard");
-
- bind(props);
- ReactiveMessageReaderSpec readerSpec = properties.buildReactiveMessageReaderSpec();
-
- assertThat(readerSpec.getTopicNames()).containsExactly("my-topic");
- assertThat(readerSpec.getReaderName()).isEqualTo("my-reader");
- assertThat(readerSpec.getSubscriptionName()).isEqualTo("my-subscription");
- assertThat(readerSpec.getGeneratedSubscriptionNamePrefix()).isEqualTo("my-prefix");
- assertThat(readerSpec.getReceiverQueueSize()).isEqualTo(1);
- assertThat(readerSpec.getReadCompacted()).isTrue();
- assertThat(readerSpec.getKeyHashRanges()).containsExactly(Range.of(2, 3));
- assertThat(readerSpec.getCryptoFailureAction()).isEqualTo(ConsumerCryptoFailureAction.DISCARD);
- }
-
- }
-
-}
diff --git a/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/SpringPulsarBootAppSanityTests.java b/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/SpringPulsarBootAppSanityTests.java
deleted file mode 100644
index 3e202e6d..00000000
--- a/spring-pulsar-spring-boot-autoconfigure/src/test/java/org/springframework/pulsar/autoconfigure/SpringPulsarBootAppSanityTests.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2022-2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.autoconfigure;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.apache.pulsar.client.api.MessageId;
-import org.apache.pulsar.client.api.PulsarClientException;
-import org.junit.jupiter.api.Test;
-
-import org.springframework.beans.factory.ObjectProvider;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.SpringBootConfiguration;
-import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
-import org.springframework.boot.test.web.client.TestRestTemplate;
-import org.springframework.pulsar.autoconfigure.SpringPulsarBootAppSanityTests.SpringPulsarBootTestApp;
-import org.springframework.pulsar.core.PulsarTemplate;
-import org.springframework.pulsar.test.support.PulsarTestContainerSupport;
-import org.springframework.test.context.DynamicPropertyRegistry;
-import org.springframework.test.context.DynamicPropertySource;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * Sanity tests to ensure that {@code Spring Pulsar} can be auto-configured into a Spring
- * Boot application.
- *
- * @author Chris Bono
- */
-@SpringBootTest(classes = SpringPulsarBootTestApp.class, webEnvironment = WebEnvironment.RANDOM_PORT)
-class SpringPulsarBootAppSanityTests implements PulsarTestContainerSupport {
-
- @DynamicPropertySource
- static void pulsarProperties(DynamicPropertyRegistry registry) {
- registry.add("spring.pulsar.client.service-url", PulsarTestContainerSupport::getPulsarBrokerUrl);
- }
-
- @Test
- void appStartsWithAutoConfiguredSpringPulsarComponents(
- @Autowired ObjectProvider> pulsarTemplate) {
- assertThat(pulsarTemplate.getIfAvailable()).isNotNull();
- }
-
- @Test
- void templateCanBeAccessedDuringWebRequest(@Autowired TestRestTemplate restTemplate) {
- String body = restTemplate.getForObject("/hello", String.class);
- assertThat(body).startsWith("Hello World -> ");
- }
-
- @SpringBootConfiguration
- @EnableAutoConfiguration
- static class SpringPulsarBootTestApp {
-
- @Autowired
- private ObjectProvider> pulsarTemplateProvider;
-
- @RestController
- class TestWebController {
-
- @GetMapping("/hello")
- String sayHello() throws PulsarClientException {
-
- PulsarTemplate pulsarTemplate = pulsarTemplateProvider.getIfAvailable();
- if (pulsarTemplate == null) {
- return "NOPE! Not hello world";
- }
- MessageId msgId = pulsarTemplate.send("spbast-hello-topic", "hello");
- return "Hello World -> " + msgId;
- }
-
- }
-
- }
-
-}
diff --git a/spring-pulsar-spring-boot-autoconfigure/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/spring-pulsar-spring-boot-autoconfigure/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
deleted file mode 100644
index 1f0955d4..00000000
--- a/spring-pulsar-spring-boot-autoconfigure/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
+++ /dev/null
@@ -1 +0,0 @@
-mock-maker-inline
diff --git a/spring-pulsar-spring-boot-starter/build.gradle b/spring-pulsar-spring-boot-starter/build.gradle
deleted file mode 100644
index 422c14de..00000000
--- a/spring-pulsar-spring-boot-starter/build.gradle
+++ /dev/null
@@ -1,11 +0,0 @@
-plugins {
- id 'org.springframework.pulsar.spring-module'
-}
-
-description = 'Spring Pulsar Spring Boot Starter'
-
-dependencies {
- api project (':spring-pulsar')
- api project (':spring-pulsar-spring-boot-autoconfigure')
- api 'org.springframework.boot:spring-boot-starter'
-}
diff --git a/spring-pulsar-spring-cloud-stream-binder/build.gradle b/spring-pulsar-spring-cloud-stream-binder/build.gradle
deleted file mode 100644
index 3e05cdd7..00000000
--- a/spring-pulsar-spring-cloud-stream-binder/build.gradle
+++ /dev/null
@@ -1,31 +0,0 @@
-plugins {
- id 'org.springframework.pulsar.spring-module'
- id 'org.springframework.pulsar.configuration-properties'
-}
-
-description = 'Spring Cloud Stream Binder for Apache Pulsar'
-
-dependencies {
- annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
-
- implementation project(':spring-pulsar-spring-boot-starter')
- api('org.springframework.cloud:spring-cloud-stream') {
- exclude group: 'javax.activation', module: 'javax.activation-api'
- exclude group: 'javax.annotation', module: 'javax.annotation-api'
- }
- testImplementation project(':spring-pulsar-test')
- testImplementation 'org.springframework.boot:spring-boot-starter-test'
- testImplementation('org.springframework.cloud:spring-cloud-stream-test-support') {
- exclude group: 'javax.activation', module: 'javax.activation-api'
- exclude group: 'javax.annotation', module: 'javax.annotation-api'
- }
- testImplementation 'org.awaitility:awaitility'
- testImplementation 'org.testcontainers:junit-jupiter'
- testImplementation 'org.testcontainers:pulsar'
-
-}
-
-test {
- testLogging.showStandardStreams = true
-}
-
diff --git a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/PulsarBinderHeaderMapper.java b/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/PulsarBinderHeaderMapper.java
deleted file mode 100644
index ddcf426f..00000000
--- a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/PulsarBinderHeaderMapper.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2018-2022 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.spring.cloud.stream.binder;
-
-import java.util.Map;
-
-import org.apache.pulsar.client.api.Message;
-
-import org.springframework.cloud.stream.binder.BinderHeaders;
-import org.springframework.integration.IntegrationMessageHeaderAccessor;
-import org.springframework.messaging.MessageHeaders;
-import org.springframework.messaging.support.MessageHeaderAccessor;
-import org.springframework.pulsar.support.header.PulsarHeaderMapper;
-
-/**
- * A delegating {@code PulsarHeaderMapper} that ensures the delegate mapper never includes
- * internal binder specific headers during outbound mapping.
- *
- * @author Chris Bono
- */
-class PulsarBinderHeaderMapper implements PulsarHeaderMapper {
-
- private final PulsarHeaderMapper delegate;
-
- /**
- * Construct a mapper with the specified delegate.
- * @param delegate the delegate mapper
- */
- PulsarBinderHeaderMapper(PulsarHeaderMapper delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public Map toPulsarHeaders(MessageHeaders springHeaders) {
- Map pulsarHeaders = this.delegate.toPulsarHeaders(springHeaders);
- pulsarHeaders.remove(MessageHeaders.ID);
- pulsarHeaders.remove(MessageHeaders.TIMESTAMP);
- pulsarHeaders.remove(IntegrationMessageHeaderAccessor.DELIVERY_ATTEMPT);
- pulsarHeaders.remove(BinderHeaders.NATIVE_HEADERS_PRESENT);
- return pulsarHeaders;
- }
-
- @Override
- public MessageHeaders toSpringHeaders(Message> pulsarMessage) {
- var springHeaders = this.delegate.toSpringHeaders(pulsarMessage);
- if (!springHeaders.isEmpty()) {
- MessageHeaderAccessor mutableHeaders = new MessageHeaderAccessor();
- mutableHeaders.copyHeaders(springHeaders);
- mutableHeaders.setHeader(BinderHeaders.NATIVE_HEADERS_PRESENT, Boolean.TRUE);
- springHeaders = mutableHeaders.getMessageHeaders();
- }
- return springHeaders;
- }
-
-}
diff --git a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/PulsarBinderUtils.java b/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/PulsarBinderUtils.java
deleted file mode 100644
index cef8b8c1..00000000
--- a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/PulsarBinderUtils.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.spring.cloud.stream.binder;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-import java.util.UUID;
-
-import org.springframework.cloud.stream.provisioning.ConsumerDestination;
-import org.springframework.core.log.LogAccessor;
-import org.springframework.pulsar.spring.cloud.stream.binder.properties.PulsarConsumerProperties;
-import org.springframework.util.StringUtils;
-
-/**
- * Binder utility methods.
- *
- * @author Soby Chacko
- * @author Chris Bono
- */
-final class PulsarBinderUtils {
-
- private static final LogAccessor LOGGER = new LogAccessor(PulsarBinderUtils.class);
-
- private static final String SUBSCRIPTION_NAME_FORMAT_STR = "%s-anon-subscription-%s";
-
- private PulsarBinderUtils() {
- }
-
- /**
- * Gets the subscription name to use for the binder.
- * @param consumerProps the pulsar consumer props
- * @param consumerDestination the destination being subscribed to
- * @return the subscription name from the consumer properties or a generated name in
- * the format {@link #SUBSCRIPTION_NAME_FORMAT_STR} when the name is not set on the
- * consumer properties
- */
- static String subscriptionName(PulsarConsumerProperties consumerProps, ConsumerDestination consumerDestination) {
- if (StringUtils.hasText(consumerProps.getSubscriptionName())) {
- return consumerProps.getSubscriptionName();
- }
- return SUBSCRIPTION_NAME_FORMAT_STR.formatted(consumerDestination.getName(), UUID.randomUUID());
- }
-
- /**
- * Merges properties defined at the binder and binding level (binding properties
- * override binder properties).
- *
- * NOTE: Properties whose value is not different from the default value in the
- * {@code baseProps} are not included in the merged result.
- * @param baseProps the map of base level properties (eg. 'spring.pulsar.consumer.*')
- * @param binderProps the map of binder level properties (eg.
- * 'spring.cloud.stream.pulsar.binder.consumer.*')
- * @param bindingProps the map of binding level properties (eg.
- * 'spring.cloud.stream.pulsar.bindings.myBinding-in-0.consumer.*')
- * @return map of merged binder and binding properties including only properties whose
- * value has changed from the same property in the base properties
- */
- static Map mergePropertiesWithPrecedence(Map baseProps,
- Map binderProps, Map bindingProps) {
- Objects.requireNonNull(baseProps, "baseProps must be specified");
- Objects.requireNonNull(binderProps, "binderProps must be specified");
- Objects.requireNonNull(bindingProps, "bindingProps must be specified");
-
- Map newOrModifiedBinderProps = extractNewOrModifiedProperties(binderProps, baseProps);
- LOGGER.trace(() -> "New or modified binder props: %s".formatted(newOrModifiedBinderProps));
-
- Map newOrModifiedBindingProps = extractNewOrModifiedProperties(bindingProps, baseProps);
- LOGGER.trace(() -> "New or modified binding props: %s".formatted(newOrModifiedBindingProps));
-
- Map mergedProps = new HashMap<>(newOrModifiedBinderProps);
- mergedProps.putAll(newOrModifiedBindingProps);
- LOGGER.trace(() -> "Final merged props: %s".formatted(mergedProps));
-
- return mergedProps;
- }
-
- private static Map extractNewOrModifiedProperties(Map candidateProps,
- Map baseProps) {
- Map newOrModifiedProps = new HashMap<>();
- candidateProps.forEach((propName, propValue) -> {
- if (!baseProps.containsKey(propName) || (!Objects.equals(propValue, baseProps.get(propName)))) {
- newOrModifiedProps.put(propName, propValue);
- }
- });
- return newOrModifiedProps;
- }
-
-}
diff --git a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/PulsarMessageChannelBinder.java b/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/PulsarMessageChannelBinder.java
deleted file mode 100644
index 288c733f..00000000
--- a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/PulsarMessageChannelBinder.java
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright 2022-2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.spring.cloud.stream.binder;
-
-import java.util.Optional;
-import java.util.Set;
-
-import org.apache.pulsar.client.api.PulsarClientException;
-import org.apache.pulsar.client.api.Schema;
-import org.apache.pulsar.common.schema.SchemaType;
-
-import org.springframework.cloud.stream.binder.AbstractMessageChannelBinder;
-import org.springframework.cloud.stream.binder.Binder;
-import org.springframework.cloud.stream.binder.BinderSpecificPropertiesProvider;
-import org.springframework.cloud.stream.binder.ExtendedConsumerProperties;
-import org.springframework.cloud.stream.binder.ExtendedProducerProperties;
-import org.springframework.cloud.stream.binder.ExtendedPropertiesBinder;
-import org.springframework.cloud.stream.binder.HeaderMode;
-import org.springframework.cloud.stream.provisioning.ConsumerDestination;
-import org.springframework.cloud.stream.provisioning.ProducerDestination;
-import org.springframework.integration.core.MessageProducer;
-import org.springframework.integration.endpoint.MessageProducerSupport;
-import org.springframework.integration.handler.AbstractMessageProducingHandler;
-import org.springframework.integration.support.management.ManageableLifecycle;
-import org.springframework.lang.Nullable;
-import org.springframework.messaging.Message;
-import org.springframework.messaging.MessageChannel;
-import org.springframework.messaging.MessageHandler;
-import org.springframework.messaging.MessageHeaders;
-import org.springframework.messaging.support.MessageBuilder;
-import org.springframework.pulsar.autoconfigure.ConsumerConfigProperties;
-import org.springframework.pulsar.autoconfigure.ProducerConfigProperties;
-import org.springframework.pulsar.core.ProducerBuilderConfigurationUtil;
-import org.springframework.pulsar.core.ProducerBuilderCustomizer;
-import org.springframework.pulsar.core.PulsarConsumerFactory;
-import org.springframework.pulsar.core.PulsarTemplate;
-import org.springframework.pulsar.core.SchemaResolver;
-import org.springframework.pulsar.core.TypedMessageBuilderCustomizer;
-import org.springframework.pulsar.listener.AbstractPulsarMessageListenerContainer;
-import org.springframework.pulsar.listener.DefaultPulsarMessageListenerContainer;
-import org.springframework.pulsar.listener.PulsarContainerProperties;
-import org.springframework.pulsar.listener.PulsarRecordMessageListener;
-import org.springframework.pulsar.spring.cloud.stream.binder.properties.PulsarBinderConfigurationProperties;
-import org.springframework.pulsar.spring.cloud.stream.binder.properties.PulsarConsumerProperties;
-import org.springframework.pulsar.spring.cloud.stream.binder.properties.PulsarExtendedBindingProperties;
-import org.springframework.pulsar.spring.cloud.stream.binder.properties.PulsarProducerProperties;
-import org.springframework.pulsar.spring.cloud.stream.binder.provisioning.PulsarTopicProvisioner;
-import org.springframework.pulsar.support.header.PulsarHeaderMapper;
-
-/**
- * {@link Binder} implementation for Apache Pulsar.
- *
- * @author Soby Chacko
- * @author Chris Bono
- */
-public class PulsarMessageChannelBinder extends
- AbstractMessageChannelBinder, ExtendedProducerProperties, PulsarTopicProvisioner>
- implements ExtendedPropertiesBinder {
-
- private final PulsarTemplate pulsarTemplate;
-
- private final PulsarConsumerFactory> pulsarConsumerFactory;
-
- private final PulsarBinderConfigurationProperties binderConfigProps;
-
- private final SchemaResolver schemaResolver;
-
- private final PulsarHeaderMapper headerMapper;
-
- private PulsarExtendedBindingProperties extendedBindingProperties = new PulsarExtendedBindingProperties();
-
- public PulsarMessageChannelBinder(PulsarTopicProvisioner provisioningProvider,
- PulsarTemplate pulsarTemplate, PulsarConsumerFactory> pulsarConsumerFactory,
- PulsarBinderConfigurationProperties binderConfigProps, SchemaResolver schemaResolver,
- PulsarHeaderMapper headerMapper) {
- super(null, provisioningProvider);
- this.pulsarTemplate = pulsarTemplate;
- this.pulsarConsumerFactory = pulsarConsumerFactory;
- this.binderConfigProps = binderConfigProps;
- this.schemaResolver = schemaResolver;
- this.headerMapper = headerMapper;
- }
-
- @Override
- protected MessageHandler createProducerMessageHandler(ProducerDestination destination,
- ExtendedProducerProperties producerProperties, MessageChannel errorChannel) {
- final Schema schema;
- if (producerProperties.isUseNativeEncoding()) {
- var schemaType = Optional.ofNullable(producerProperties.getExtension().getSchemaType())
- .orElse(SchemaType.NONE);
- schema = this.schemaResolver
- .resolveSchema(schemaType, producerProperties.getExtension().getMessageType(),
- producerProperties.getExtension().getMessageKeyType())
- .orElseThrow(() -> "Could not determine producer schema for " + destination.getName());
- }
- else {
- schema = null;
- }
- var baseProducerProps = new ProducerConfigProperties().buildProperties();
- var binderProducerProps = this.binderConfigProps.getProducer().buildProperties();
- var bindingProducerProps = producerProperties.getExtension().buildProperties();
- var mergedProducerProps = PulsarBinderUtils.mergePropertiesWithPrecedence(baseProducerProps,
- binderProducerProps, bindingProducerProps);
-
- var handler = new PulsarProducerConfigurationMessageHandler(this.pulsarTemplate, schema, destination.getName(),
- (builder) -> ProducerBuilderConfigurationUtil.loadConf(builder, mergedProducerProps),
- determineOutboundHeaderMapper(producerProperties));
- handler.setApplicationContext(getApplicationContext());
- handler.setBeanFactory(getBeanFactory());
-
- return handler;
- }
-
- @Nullable
- private PulsarBinderHeaderMapper determineOutboundHeaderMapper(
- ExtendedProducerProperties extProducerProps) {
- if (HeaderMode.none.equals(extProducerProps.getHeaderMode())) {
- return null;
- }
- return new PulsarBinderHeaderMapper(this.headerMapper);
- }
-
- @Override
- protected MessageProducer createConsumerEndpoint(ConsumerDestination destination, String group,
- ExtendedConsumerProperties properties) {
- var containerProperties = new PulsarContainerProperties();
- containerProperties.setTopics(Set.of(destination.getName()));
-
- var inboundHeaderMapper = determineInboundHeaderMapper(properties);
-
- var messageDrivenChannelAdapter = new PulsarMessageDrivenChannelAdapter();
- containerProperties.setMessageListener((PulsarRecordMessageListener>) (consumer, pulsarMsg) -> {
- var springMessage = (inboundHeaderMapper != null)
- ? MessageBuilder.createMessage(pulsarMsg.getValue(), inboundHeaderMapper.toSpringHeaders(pulsarMsg))
- : MessageBuilder.withPayload(pulsarMsg.getValue()).build();
- messageDrivenChannelAdapter.send(springMessage);
- });
-
- if (properties.isUseNativeDecoding()) {
- var schemaType = Optional.ofNullable(properties.getExtension().getSchemaType()).orElse(SchemaType.NONE);
- var schema = this.schemaResolver
- .resolveSchema(schemaType, properties.getExtension().getMessageType(),
- properties.getExtension().getMessageKeyType())
- .orElseThrow(() -> "Could not determine consumer schema for " + destination.getName());
- containerProperties.setSchema(schema);
- }
- else {
- containerProperties.setSchema(Schema.BYTES);
- }
- var subscriptionName = PulsarBinderUtils.subscriptionName(properties.getExtension(), destination);
- containerProperties.setSubscriptionName(subscriptionName);
-
- var baseConsumerProps = new ConsumerConfigProperties().buildProperties();
- var binderConsumerProps = this.binderConfigProps.getConsumer().buildProperties();
- var bindingConsumerProps = properties.getExtension().buildProperties();
- var mergedConsumerProps = PulsarBinderUtils.mergePropertiesWithPrecedence(baseConsumerProps,
- binderConsumerProps, bindingConsumerProps);
- containerProperties.getPulsarConsumerProperties().putAll(mergedConsumerProps);
- containerProperties.updateContainerProperties();
-
- var container = new DefaultPulsarMessageListenerContainer<>(this.pulsarConsumerFactory, containerProperties);
- messageDrivenChannelAdapter.setMessageListenerContainer(container);
-
- return messageDrivenChannelAdapter;
- }
-
- @Nullable
- private PulsarBinderHeaderMapper determineInboundHeaderMapper(
- ExtendedConsumerProperties extConsumerProps) {
- if (HeaderMode.none.equals(extConsumerProps.getHeaderMode())) {
- return null;
- }
- return new PulsarBinderHeaderMapper(this.headerMapper);
- }
-
- @Override
- public PulsarConsumerProperties getExtendedConsumerProperties(String channelName) {
- return this.extendedBindingProperties.getExtendedConsumerProperties(channelName);
- }
-
- @Override
- public PulsarProducerProperties getExtendedProducerProperties(String channelName) {
- return this.extendedBindingProperties.getExtendedProducerProperties(channelName);
- }
-
- @Override
- public String getDefaultsPrefix() {
- return null;
- }
-
- @Override
- public Class extends BinderSpecificPropertiesProvider> getExtendedPropertiesEntryClass() {
- return null;
- }
-
- public PulsarExtendedBindingProperties getExtendedBindingProperties() {
- return this.extendedBindingProperties;
- }
-
- public void setExtendedBindingProperties(PulsarExtendedBindingProperties extendedBindingProperties) {
- this.extendedBindingProperties = extendedBindingProperties;
- }
-
- static class PulsarMessageDrivenChannelAdapter extends MessageProducerSupport {
-
- AbstractPulsarMessageListenerContainer> messageListenerContainer;
-
- public void send(Message> message) {
- sendMessage(message);
- }
-
- @Override
- protected void doStart() {
- this.messageListenerContainer.start();
- }
-
- @Override
- protected void doStop() {
- this.messageListenerContainer.stop();
- }
-
- public void setMessageListenerContainer(AbstractPulsarMessageListenerContainer> messageListenerContainer) {
- this.messageListenerContainer = messageListenerContainer;
- }
-
- }
-
- static class PulsarProducerConfigurationMessageHandler extends AbstractMessageProducingHandler
- implements ManageableLifecycle {
-
- private final PulsarTemplate pulsarTemplate;
-
- private final Schema schema;
-
- private final String destination;
-
- private final ProducerBuilderCustomizer layeredProducerPropsCustomizer;
-
- private final PulsarHeaderMapper headerMapper;
-
- private boolean running = true;
-
- PulsarProducerConfigurationMessageHandler(PulsarTemplate pulsarTemplate, Schema schema,
- String destination, ProducerBuilderCustomizer layeredProducerPropsCustomizer,
- PulsarHeaderMapper headerMapper) {
- this.pulsarTemplate = pulsarTemplate;
- this.schema = schema;
- this.destination = destination;
- this.layeredProducerPropsCustomizer = layeredProducerPropsCustomizer;
- this.headerMapper = headerMapper;
- }
-
- @Override
- public void start() {
- try {
- super.onInit();
- }
- catch (Exception ex) {
- this.logger.error(ex, "Initialization errors: ");
- throw new RuntimeException(ex);
- }
- }
-
- @Override
- public void stop() {
- // TODO - should we close the underlyiung producer?
- this.running = false;
- }
-
- @Override
- public boolean isRunning() {
- return this.running;
- }
-
- @Override
- protected void handleMessageInternal(Message> message) {
- try {
- // @formatter:off
- this.pulsarTemplate.newMessage(message.getPayload())
- .withTopic(this.destination)
- .withSchema(this.schema)
- .withProducerCustomizer(this.layeredProducerPropsCustomizer)
- .withMessageCustomizer(this.applySpringHeadersAsPulsarProperties(message.getHeaders()))
- .sendAsync();
- // @formatter:on
- }
- catch (PulsarClientException ex) {
- logger.trace(ex, "Failed to send message to destination: " + this.destination);
- }
- }
-
- private TypedMessageBuilderCustomizer applySpringHeadersAsPulsarProperties(MessageHeaders headers) {
- return (mb) -> {
- if (this.headerMapper != null) {
- this.headerMapper.toPulsarHeaders(headers).forEach(mb::property);
- }
- };
- }
-
- }
-
-}
diff --git a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/config/PulsarBinderConfiguration.java b/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/config/PulsarBinderConfiguration.java
deleted file mode 100644
index 1845e871..00000000
--- a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/config/PulsarBinderConfiguration.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.spring.cloud.stream.binder.config;
-
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.cloud.stream.binder.Binder;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.pulsar.autoconfigure.PulsarProperties;
-import org.springframework.pulsar.core.PulsarAdministration;
-import org.springframework.pulsar.core.PulsarConsumerFactory;
-import org.springframework.pulsar.core.PulsarTemplate;
-import org.springframework.pulsar.core.SchemaResolver;
-import org.springframework.pulsar.spring.cloud.stream.binder.PulsarMessageChannelBinder;
-import org.springframework.pulsar.spring.cloud.stream.binder.properties.PulsarBinderConfigurationProperties;
-import org.springframework.pulsar.spring.cloud.stream.binder.properties.PulsarExtendedBindingProperties;
-import org.springframework.pulsar.spring.cloud.stream.binder.provisioning.PulsarTopicProvisioner;
-import org.springframework.pulsar.support.header.JacksonUtils;
-import org.springframework.pulsar.support.header.JsonPulsarHeaderMapper;
-import org.springframework.pulsar.support.header.PulsarHeaderMapper;
-import org.springframework.pulsar.support.header.ToStringPulsarHeaderMapper;
-
-/**
- * Pulsar binder {@link Configuration}.
- *
- * @author Soby Chacko
- */
-@Configuration(proxyBeanMethods = false)
-@ConditionalOnMissingBean(Binder.class)
-@EnableConfigurationProperties({ PulsarProperties.class, PulsarExtendedBindingProperties.class,
- PulsarBinderConfigurationProperties.class })
-public class PulsarBinderConfiguration {
-
- @Bean
- public PulsarTopicProvisioner pulsarTopicProvisioner(PulsarAdministration pulsarAdministration,
- PulsarBinderConfigurationProperties pulsarBinderConfigurationProperties) {
- return new PulsarTopicProvisioner(pulsarAdministration, pulsarBinderConfigurationProperties);
- }
-
- @Bean
- @ConditionalOnMissingBean
- public PulsarHeaderMapper pulsarHeaderMapper() {
- if (JacksonUtils.isJacksonPresent()) {
- return JsonPulsarHeaderMapper.builder().build();
- }
- return new ToStringPulsarHeaderMapper();
- }
-
- @Bean
- public PulsarMessageChannelBinder pulsarMessageChannelBinder(PulsarTopicProvisioner pulsarTopicProvisioner,
- PulsarTemplate pulsarTemplate, PulsarConsumerFactory pulsarConsumerFactory,
- PulsarBinderConfigurationProperties binderConfigProps, PulsarExtendedBindingProperties bindingConfigProps,
- SchemaResolver schemaResolver, PulsarHeaderMapper headerMapper) {
- PulsarMessageChannelBinder pulsarMessageChannelBinder = new PulsarMessageChannelBinder(pulsarTopicProvisioner,
- pulsarTemplate, pulsarConsumerFactory, binderConfigProps, schemaResolver, headerMapper);
- pulsarMessageChannelBinder.setExtendedBindingProperties(bindingConfigProps);
- return pulsarMessageChannelBinder;
- }
-
-}
diff --git a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/package-info.java b/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/package-info.java
deleted file mode 100644
index 0b0aa4e1..00000000
--- a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/package-info.java
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * Package containing Spring Cloud Stream binder classes for Apache Pulsar.
- */
-@NonNullApi
-@NonNullFields
-package org.springframework.pulsar.spring.cloud.stream.binder;
-
-import org.springframework.lang.NonNullApi;
-import org.springframework.lang.NonNullFields;
diff --git a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/properties/PulsarBinderConfigurationProperties.java b/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/properties/PulsarBinderConfigurationProperties.java
deleted file mode 100644
index b7b5f53e..00000000
--- a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/properties/PulsarBinderConfigurationProperties.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.spring.cloud.stream.binder.properties;
-
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.boot.context.properties.NestedConfigurationProperty;
-import org.springframework.lang.Nullable;
-import org.springframework.pulsar.autoconfigure.ConsumerConfigProperties;
-import org.springframework.pulsar.autoconfigure.ProducerConfigProperties;
-
-/**
- * {@link ConfigurationProperties @ConfigurationProperties} for the Pulsar binder.
- *
- * These properties are applied at the binder level (to all bindings).
- *
- * @author Soby Chacko
- * @author Chris Bono
- */
-@ConfigurationProperties(prefix = "spring.cloud.stream.pulsar.binder")
-public class PulsarBinderConfigurationProperties {
-
- /**
- * Pulsar consumer specific binder-level properties (applied to all bindings).
- */
- @NestedConfigurationProperty
- private final ConsumerConfigProperties consumer = new ConsumerConfigProperties();
-
- /**
- * Pulsar producer specific binder-level properties (applied to all bindings).
- */
- @NestedConfigurationProperty
- private final ProducerConfigProperties producer = new ProducerConfigProperties();
-
- /**
- * Number of topic partitions.
- */
- @Nullable
- private Integer partitionCount;
-
- public ConsumerConfigProperties getConsumer() {
- return this.consumer;
- }
-
- public ProducerConfigProperties getProducer() {
- return this.producer;
- }
-
- @Nullable
- public Integer getPartitionCount() {
- return this.partitionCount;
- }
-
- public void setPartitionCount(Integer partitionCount) {
- this.partitionCount = partitionCount;
- }
-
-}
diff --git a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/properties/PulsarBindingProperties.java b/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/properties/PulsarBindingProperties.java
deleted file mode 100644
index d4e6e224..00000000
--- a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/properties/PulsarBindingProperties.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.spring.cloud.stream.binder.properties;
-
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.boot.context.properties.NestedConfigurationProperty;
-import org.springframework.cloud.stream.binder.BinderSpecificPropertiesProvider;
-
-/**
- * Container for Pulsar specific extended producer and consumer binding properties.
- *
- * These properties are applied to individual bindings and will override any binder-level
- * setting.
- *
- *
- * NOTE: This class is only referenced as a value in the
- * {@link PulsarExtendedBindingProperties#getBindings() bindings map} and therefore, by
- * default is not included in the generated configuration metadata. To get around this
- * limitation it is annotated with {@code @ConfigurationProperties}. However, that is the
- * only reason it is annotated and is not intended to be used directly.
- *
- * @author Soby Chacko
- * @author Chris Bono
- */
-@SuppressWarnings("ConfigurationProperties")
-@ConfigurationProperties("spring.cloud.stream.pulsar.bindings.for-docs-only")
-public class PulsarBindingProperties implements BinderSpecificPropertiesProvider {
-
- /**
- * Pulsar consumer specific binding properties.
- */
- @NestedConfigurationProperty
- private PulsarConsumerProperties consumer = new PulsarConsumerProperties();
-
- /**
- * Pulsar producer specific binding properties.
- */
- @NestedConfigurationProperty
- private PulsarProducerProperties producer = new PulsarProducerProperties();
-
- public PulsarConsumerProperties getConsumer() {
- return this.consumer;
- }
-
- public void setConsumer(PulsarConsumerProperties consumer) {
- this.consumer = consumer;
- }
-
- public PulsarProducerProperties getProducer() {
- return this.producer;
- }
-
- public void setProducer(PulsarProducerProperties producer) {
- this.producer = producer;
- }
-
-}
diff --git a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/properties/PulsarConsumerProperties.java b/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/properties/PulsarConsumerProperties.java
deleted file mode 100644
index d360c31c..00000000
--- a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/properties/PulsarConsumerProperties.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2022-2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.spring.cloud.stream.binder.properties;
-
-import org.apache.pulsar.common.schema.SchemaType;
-
-import org.springframework.lang.Nullable;
-import org.springframework.pulsar.autoconfigure.ConsumerConfigProperties;
-
-/**
- * Pulsar consumer properties used by the binder.
- *
- * @author Soby Chacko
- * @author Chris Bono
- */
-public class PulsarConsumerProperties extends ConsumerConfigProperties {
-
- /**
- * Pulsar {@link SchemaType} for this binding.
- */
- @Nullable
- private SchemaType schemaType;
-
- /**
- * Pulsar message type for this binding.
- */
- @Nullable
- private Class> messageType;
-
- /**
- * Pulsar message key type for this binding (only used when schema type is
- * {@code }KEY_VALUE}).
- */
- @Nullable
- private Class> messageKeyType;
-
- /**
- * Number of topic partitions.
- */
- @Nullable
- private Integer partitionCount;
-
- @Nullable
- public SchemaType getSchemaType() {
- return this.schemaType;
- }
-
- public void setSchemaType(@Nullable SchemaType schemaType) {
- this.schemaType = schemaType;
- }
-
- @Nullable
- public Class> getMessageType() {
- return this.messageType;
- }
-
- public void setMessageType(@Nullable Class> messageType) {
- this.messageType = messageType;
- }
-
- @Nullable
- public Class> getMessageKeyType() {
- return this.messageKeyType;
- }
-
- public void setMessageKeyType(@Nullable Class> messageKeyType) {
- this.messageKeyType = messageKeyType;
- }
-
- @Nullable
- public Integer getPartitionCount() {
- return this.partitionCount;
- }
-
- public void setPartitionCount(Integer partitionCount) {
- this.partitionCount = partitionCount;
- }
-
-}
diff --git a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/properties/PulsarExtendedBindingProperties.java b/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/properties/PulsarExtendedBindingProperties.java
deleted file mode 100644
index 64efe70a..00000000
--- a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/properties/PulsarExtendedBindingProperties.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.spring.cloud.stream.binder.properties;
-
-import java.util.Map;
-
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.cloud.stream.binder.AbstractExtendedBindingProperties;
-import org.springframework.cloud.stream.binder.BinderSpecificPropertiesProvider;
-
-/**
- * {@link ConfigurationProperties @ConfigurationProperties} for Pulsar binder specific
- * extensions to the common binding properties.
- *
- * These properties are applied to individual bindings and will override any binder-level
- * settings.
- *
- * @author Soby Chacko
- * @author Chris Bono
- */
-@ConfigurationProperties("spring.cloud.stream.pulsar")
-public class PulsarExtendedBindingProperties extends
- AbstractExtendedBindingProperties {
-
- private static final String DEFAULTS_PREFIX = "spring.cloud.stream.pulsar.default";
-
- @Override
- public String getDefaultsPrefix() {
- return DEFAULTS_PREFIX;
- }
-
- /**
- * Properties per individual binding name (e.g. 'mySink-in-0').
- */
- @Override
- public Map getBindings() {
- return this.doGetBindings();
- }
-
- @Override
- public Class extends BinderSpecificPropertiesProvider> getExtendedPropertiesEntryClass() {
- return PulsarBindingProperties.class;
- }
-
-}
diff --git a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/properties/PulsarProducerProperties.java b/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/properties/PulsarProducerProperties.java
deleted file mode 100644
index d5537d7a..00000000
--- a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/properties/PulsarProducerProperties.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2022-2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.spring.cloud.stream.binder.properties;
-
-import org.apache.pulsar.common.schema.SchemaType;
-
-import org.springframework.lang.Nullable;
-import org.springframework.pulsar.autoconfigure.ProducerConfigProperties;
-
-/**
- * Pulsar producer properties used by the binder.
- *
- * @author Soby Chacko
- * @author Chris Bono
- */
-public class PulsarProducerProperties extends ProducerConfigProperties {
-
- /**
- * Pulsar {@link SchemaType} for this binding.
- */
- @Nullable
- private SchemaType schemaType;
-
- /**
- * Pulsar message type for this binding.
- */
- @Nullable
- private Class> messageType;
-
- /**
- * Pulsar message key type for this binding (only used when schema type is
- * {@code }KEY_VALUE}).
- */
- @Nullable
- private Class> messageKeyType;
-
- /**
- * Number of topic partitions.
- */
- @Nullable
- private Integer partitionCount;
-
- @Nullable
- public SchemaType getSchemaType() {
- return this.schemaType;
- }
-
- public void setSchemaType(@Nullable SchemaType schemaType) {
- this.schemaType = schemaType;
- }
-
- @Nullable
- public Class> getMessageType() {
- return this.messageType;
- }
-
- public void setMessageType(@Nullable Class> messageType) {
- this.messageType = messageType;
- }
-
- @Nullable
- public Class> getMessageKeyType() {
- return this.messageKeyType;
- }
-
- public void setMessageKeyType(@Nullable Class> messageKeyType) {
- this.messageKeyType = messageKeyType;
- }
-
- @Nullable
- public Integer getPartitionCount() {
- return this.partitionCount;
- }
-
- public void setPartitionCount(Integer partitionCount) {
- this.partitionCount = partitionCount;
- }
-
-}
diff --git a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/properties/package-info.java b/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/properties/package-info.java
deleted file mode 100644
index 7d964d12..00000000
--- a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/properties/package-info.java
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * Package containing Spring Cloud Stream binder properties classes for Apache Pulsar.
- */
-@NonNullApi
-@NonNullFields
-package org.springframework.pulsar.spring.cloud.stream.binder.properties;
-
-import org.springframework.lang.NonNullApi;
-import org.springframework.lang.NonNullFields;
diff --git a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/provisioning/PulsarTopicProvisioner.java b/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/provisioning/PulsarTopicProvisioner.java
deleted file mode 100644
index b4fee3d7..00000000
--- a/spring-pulsar-spring-cloud-stream-binder/src/main/java/org/springframework/pulsar/spring/cloud/stream/binder/provisioning/PulsarTopicProvisioner.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2022-2023 the original author or authors.
- *
- * Licensed 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
- *
- * https://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.springframework.pulsar.spring.cloud.stream.binder.provisioning;
-
-import org.springframework.cloud.stream.binder.ExtendedConsumerProperties;
-import org.springframework.cloud.stream.binder.ExtendedProducerProperties;
-import org.springframework.cloud.stream.provisioning.ConsumerDestination;
-import org.springframework.cloud.stream.provisioning.ProducerDestination;
-import org.springframework.cloud.stream.provisioning.ProvisioningException;
-import org.springframework.cloud.stream.provisioning.ProvisioningProvider;
-import org.springframework.lang.Nullable;
-import org.springframework.pulsar.core.PulsarAdministration;
-import org.springframework.pulsar.core.PulsarTopic;
-import org.springframework.pulsar.spring.cloud.stream.binder.properties.PulsarBinderConfigurationProperties;
-import org.springframework.pulsar.spring.cloud.stream.binder.properties.PulsarConsumerProperties;
-import org.springframework.pulsar.spring.cloud.stream.binder.properties.PulsarProducerProperties;
-
-/**
- * Pulsar topic provisioner.
- *
- * @author Soby Chacko
- */
-public class PulsarTopicProvisioner implements
- ProvisioningProvider, ExtendedProducerProperties> {
-
- private final PulsarAdministration pulsarAdministration;
-
- private final PulsarBinderConfigurationProperties pulsarBinderConfigurationProperties;
-
- public PulsarTopicProvisioner(PulsarAdministration pulsarAdministration,
- PulsarBinderConfigurationProperties pulsarBinderConfigurationProperties) {
- this.pulsarAdministration = pulsarAdministration;
- this.pulsarBinderConfigurationProperties = pulsarBinderConfigurationProperties;
- }
-
- @Override
- public ProducerDestination provisionProducerDestination(String name,
- ExtendedProducerProperties pulsarProducerProperties)
- throws ProvisioningException {
- Integer partitionCountFromBinding = pulsarProducerProperties.getExtension().getPartitionCount();
- var partitionCount = getPartitionCount(partitionCountFromBinding);
- var pulsarTopic = PulsarTopic.builder(name).numberOfPartitions(partitionCount).build();
- this.pulsarAdministration.createOrModifyTopics(pulsarTopic);
- return new PulsarDestination(pulsarTopic.topicName(), pulsarTopic.numberOfPartitions());
- }
-
- private int getPartitionCount(@Nullable Integer partitionCountConfig) {
- var partitionCount = this.pulsarBinderConfigurationProperties.getPartitionCount();
- if (partitionCountConfig != null && partitionCountConfig > 0) {
- partitionCount = partitionCountConfig;
- }
- return partitionCount == null ? 0 : partitionCount;
- }
-
- @Override
- public ConsumerDestination provisionConsumerDestination(String name, String group,
- ExtendedConsumerProperties