Fix new and some old Sonar smells
This commit is contained in:
@@ -37,6 +37,7 @@ import org.springframework.util.Assert;
|
||||
* Pollable channel backed by a Kafka topic.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 5.4
|
||||
*
|
||||
@@ -68,8 +69,9 @@ public class PollableKafkaChannel extends AbstractKafkaChannel
|
||||
|
||||
private static String topic(KafkaMessageSource<?, ?> source) {
|
||||
Assert.notNull(source, "'source' cannot be null");
|
||||
Assert.isTrue(source.getConsumerProperties().getTopics().length == 1, "Only one topic is allowed");
|
||||
return source.getConsumerProperties().getTopics()[0];
|
||||
String[] topics = source.getConsumerProperties().getTopics();
|
||||
Assert.isTrue(topics != null && topics.length == 1, "Only one topic is allowed");
|
||||
return topics[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.springframework.integration.kafka.channel;
|
||||
import org.apache.kafka.clients.consumer.Consumer;
|
||||
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
||||
|
||||
import org.springframework.context.Phased;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.integration.dispatcher.MessageDispatcher;
|
||||
import org.springframework.integration.dispatcher.RoundRobinLoadBalancingStrategy;
|
||||
@@ -37,6 +36,7 @@ import org.springframework.util.Assert;
|
||||
* Subscribable channel backed by a Kafka topic.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 5.4
|
||||
*
|
||||
@@ -79,7 +79,7 @@ public class SubscribableKafkaChannel extends AbstractKafkaChannel implements Su
|
||||
/**
|
||||
* Set the phase.
|
||||
* @param phase the phase.
|
||||
* @see Phased
|
||||
* @see org.springframework.context.Phased
|
||||
*/
|
||||
public void setPhase(int phase) {
|
||||
this.phase = phase;
|
||||
|
||||
@@ -18,8 +18,6 @@ package org.springframework.integration.kafka.dsl;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.kafka.common.TopicPartition;
|
||||
|
||||
import org.springframework.integration.kafka.inbound.KafkaMessageDrivenChannelAdapter;
|
||||
import org.springframework.integration.kafka.inbound.KafkaMessageSource;
|
||||
import org.springframework.integration.kafka.inbound.KafkaMessageSource.KafkaAckCallbackFactory;
|
||||
@@ -225,7 +223,7 @@ public final class Kafka {
|
||||
* Create an initial
|
||||
* {@link KafkaMessageDrivenChannelAdapterSpec.KafkaMessageDrivenChannelAdapterListenerContainerSpec}.
|
||||
* @param consumerFactory the {@link ConsumerFactory}.
|
||||
* @param topicPartitions the {@link TopicPartition} vararg.
|
||||
* @param topicPartitions the {@link TopicPartitionOffset} vararg.
|
||||
* @param <K> the Kafka message key type.
|
||||
* @param <V> the Kafka message value type.
|
||||
* @return the KafkaMessageDrivenChannelAdapterSpec.KafkaMessageDrivenChannelAdapterListenerContainerSpec.
|
||||
@@ -244,7 +242,7 @@ public final class Kafka {
|
||||
* {@link KafkaMessageDrivenChannelAdapterSpec.KafkaMessageDrivenChannelAdapterListenerContainerSpec}.
|
||||
* @param consumerFactory the {@link ConsumerFactory}.
|
||||
* @param listenerMode the {@link KafkaMessageDrivenChannelAdapter.ListenerMode}.
|
||||
* @param topicPartitions the {@link TopicPartition} vararg.
|
||||
* @param topicPartitions the {@link TopicPartitionOffset} vararg.
|
||||
* @param <K> the Kafka message key type.
|
||||
* @param <V> the Kafka message value type.
|
||||
* @return the KafkaMessageDrivenChannelAdapterSpec.KafkaMessageDrivenChannelAdapterListenerContainerSpec.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2019 the original author or authors.
|
||||
* Copyright 2018-2020 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.
|
||||
@@ -16,16 +16,11 @@
|
||||
|
||||
package org.springframework.integration.kafka.dsl;
|
||||
|
||||
import org.apache.kafka.clients.consumer.ConsumerRecord;
|
||||
|
||||
import org.springframework.integration.IntegrationMessageHeaderAccessor;
|
||||
import org.springframework.integration.dsl.MessageSourceSpec;
|
||||
import org.springframework.integration.kafka.inbound.KafkaMessageSource;
|
||||
import org.springframework.integration.kafka.inbound.KafkaMessageSource.KafkaAckCallbackFactory;
|
||||
import org.springframework.kafka.core.ConsumerFactory;
|
||||
import org.springframework.kafka.listener.ConsumerProperties;
|
||||
import org.springframework.kafka.support.KafkaHeaders;
|
||||
import org.springframework.kafka.support.converter.MessagingMessageConverter;
|
||||
import org.springframework.kafka.support.converter.RecordMessageConverter;
|
||||
|
||||
/**
|
||||
@@ -36,6 +31,7 @@ import org.springframework.kafka.support.converter.RecordMessageConverter;
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @author Anshul Mehra
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 5.4
|
||||
*
|
||||
@@ -72,7 +68,7 @@ public class KafkaInboundChannelAdapterSpec<K, V>
|
||||
|
||||
/**
|
||||
* Set the message converter to replace the default.
|
||||
* {@link MessagingMessageConverter}.
|
||||
* {@link org.springframework.kafka.support.converter.MessagingMessageConverter}.
|
||||
* @param messageConverter the converter.
|
||||
* @return the spec.
|
||||
*/
|
||||
@@ -93,9 +89,9 @@ public class KafkaInboundChannelAdapterSpec<K, V>
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true to include the raw {@link ConsumerRecord} as headers with keys
|
||||
* {@link KafkaHeaders#RAW_DATA} and
|
||||
* {@link IntegrationMessageHeaderAccessor#SOURCE_DATA}. enabling callers to have
|
||||
* Set to true to include the raw {@link org.apache.kafka.clients.consumer.ConsumerRecord} as headers with keys
|
||||
* {@link org.springframework.kafka.support.KafkaHeaders#RAW_DATA} and
|
||||
* {@link org.springframework.integration.IntegrationMessageHeaderAccessor#SOURCE_DATA}. enabling callers to have
|
||||
* access to the record to process errors.
|
||||
* @param rawMessageHeader true to include the header.
|
||||
* @return the spec.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2019 the original author or authors.
|
||||
* Copyright 2018-2020 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.
|
||||
@@ -29,7 +29,6 @@ import org.springframework.integration.kafka.inbound.KafkaInboundGateway;
|
||||
import org.springframework.integration.support.ObjectStringMapBuilder;
|
||||
import org.springframework.kafka.core.KafkaTemplate;
|
||||
import org.springframework.kafka.listener.AbstractMessageListenerContainer;
|
||||
import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;
|
||||
import org.springframework.kafka.listener.ConsumerSeekAware;
|
||||
import org.springframework.kafka.support.converter.RecordMessageConverter;
|
||||
import org.springframework.retry.RecoveryCallback;
|
||||
@@ -116,8 +115,8 @@ public class KafkaInboundGatewaySpec<K, V, R, S extends KafkaInboundGatewaySpec<
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link ConcurrentMessageListenerContainer} configuration {@link KafkaInboundGatewaySpec}
|
||||
* extension.
|
||||
* A {@link org.springframework.kafka.listener.ConcurrentMessageListenerContainer}
|
||||
* configuration {@link KafkaInboundGatewaySpec} extension.
|
||||
* @param <K> the key type.
|
||||
* @param <V> the request value type.
|
||||
* @param <R> the reply value type.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-2020 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.
|
||||
@@ -27,7 +27,6 @@ import org.springframework.integration.dsl.ComponentsRegistration;
|
||||
import org.springframework.integration.dsl.MessageProducerSpec;
|
||||
import org.springframework.integration.kafka.inbound.KafkaMessageDrivenChannelAdapter;
|
||||
import org.springframework.kafka.listener.AbstractMessageListenerContainer;
|
||||
import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;
|
||||
import org.springframework.kafka.listener.ConsumerSeekAware;
|
||||
import org.springframework.kafka.listener.adapter.RecordFilterStrategy;
|
||||
import org.springframework.kafka.support.converter.BatchMessageConverter;
|
||||
@@ -193,8 +192,8 @@ public class KafkaMessageDrivenChannelAdapterSpec<K, V, S extends KafkaMessageDr
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link ConcurrentMessageListenerContainer} configuration {@link KafkaMessageDrivenChannelAdapterSpec}
|
||||
* extension.
|
||||
* A {@link org.springframework.kafka.listener.ConcurrentMessageListenerContainer} configuration
|
||||
* {@link KafkaMessageDrivenChannelAdapterSpec} extension.
|
||||
* @param <K> the key type.
|
||||
* @param <V> the value type.
|
||||
*/
|
||||
|
||||
@@ -24,11 +24,8 @@ import org.apache.kafka.clients.consumer.OffsetCommitCallback;
|
||||
import org.springframework.core.task.AsyncListenableTaskExecutor;
|
||||
import org.springframework.integration.dsl.IntegrationComponentSpec;
|
||||
import org.springframework.kafka.core.ConsumerFactory;
|
||||
import org.springframework.kafka.listener.AbstractMessageListenerContainer;
|
||||
import org.springframework.kafka.listener.AcknowledgingMessageListener;
|
||||
import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;
|
||||
import org.springframework.kafka.listener.ContainerProperties;
|
||||
import org.springframework.kafka.listener.ErrorHandler;
|
||||
import org.springframework.kafka.listener.GenericErrorHandler;
|
||||
import org.springframework.kafka.support.TopicPartitionOffset;
|
||||
|
||||
@@ -68,12 +65,13 @@ public class KafkaMessageListenerContainerSpec<K, V>
|
||||
}
|
||||
|
||||
@Override
|
||||
public KafkaMessageListenerContainerSpec<K, V> id(String id) {
|
||||
public KafkaMessageListenerContainerSpec<K, V> id(String id) { // NOSONAR - increase visibility
|
||||
return super.id(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a concurrency maximum number for the {@link AbstractMessageListenerContainer}.
|
||||
* Specify a concurrency maximum number for the
|
||||
* {@link org.springframework.kafka.listener.AbstractMessageListenerContainer}.
|
||||
* @param concurrency the concurrency maximum number.
|
||||
* @return the spec.
|
||||
* @see ConcurrentMessageListenerContainer#setConcurrency(int)
|
||||
@@ -84,10 +82,11 @@ public class KafkaMessageListenerContainerSpec<K, V>
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify an {@link ErrorHandler} for the {@link AbstractMessageListenerContainer}.
|
||||
* @param errorHandler the {@link ErrorHandler}.
|
||||
* Specify an {@link org.springframework.kafka.listener.ErrorHandler} for the
|
||||
* {@link org.springframework.kafka.listener.AbstractMessageListenerContainer}.
|
||||
* @param errorHandler the {@link org.springframework.kafka.listener.ErrorHandler}.
|
||||
* @return the spec.
|
||||
* @see ErrorHandler
|
||||
* @see org.springframework.kafka.listener.ErrorHandler
|
||||
*/
|
||||
public KafkaMessageListenerContainerSpec<K, V> errorHandler(GenericErrorHandler<?> errorHandler) {
|
||||
this.target.setGenericErrorHandler(errorHandler);
|
||||
@@ -104,7 +103,7 @@ public class KafkaMessageListenerContainerSpec<K, V>
|
||||
* {@code #setPollTimeout(long) pollTimeout}.</li>
|
||||
* <li>COUNT: Ack after at least this number of records have been received</li>
|
||||
* <li>MANUAL: Listener is responsible for acking - use a
|
||||
* {@link AcknowledgingMessageListener}.
|
||||
* {@link org.springframework.kafka.listener.AcknowledgingMessageListener}.
|
||||
* </ul>
|
||||
* @param ackMode the {@link ContainerProperties.AckMode}; default BATCH.
|
||||
* @return the spec.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2019 the original author or authors.
|
||||
* Copyright 2018-2020 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.
|
||||
@@ -22,10 +22,6 @@ import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.integration.dsl.ComponentsRegistration;
|
||||
import org.springframework.integration.dsl.IntegrationComponentSpec;
|
||||
import org.springframework.integration.dsl.MessageHandlerSpec;
|
||||
import org.springframework.integration.kafka.outbound.KafkaProducerMessageHandler;
|
||||
import org.springframework.kafka.core.KafkaTemplate;
|
||||
import org.springframework.kafka.core.ProducerFactory;
|
||||
import org.springframework.kafka.listener.GenericMessageListenerContainer;
|
||||
import org.springframework.kafka.requestreply.ReplyingKafkaTemplate;
|
||||
@@ -34,7 +30,8 @@ import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandlerSpec} implementation for the {@link KafkaProducerMessageHandler}
|
||||
* A {@link org.springframework.integration.dsl.MessageHandlerSpec}
|
||||
* implementation for the {@link org.springframework.integration.kafka.outbound.KafkaProducerMessageHandler}
|
||||
* as a gateway.
|
||||
* @param <K> the key type.
|
||||
* @param <V> the outbound value type.
|
||||
@@ -64,7 +61,7 @@ public class KafkaOutboundGatewaySpec<K, V, R, S extends KafkaOutboundGatewaySpe
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link KafkaTemplate}-based {@link KafkaProducerMessageHandlerSpec} extension.
|
||||
* A {@link org.springframework.kafka.core.KafkaTemplate}-based {@link KafkaProducerMessageHandlerSpec} extension.
|
||||
*
|
||||
* @param <K> the key type.
|
||||
* @param <V> the outbound value type.
|
||||
@@ -107,7 +104,8 @@ public class KafkaOutboundGatewaySpec<K, V, R, S extends KafkaOutboundGatewaySpe
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link IntegrationComponentSpec} implementation for the {@link KafkaTemplate}.
|
||||
* An {@link org.springframework.integration.dsl.IntegrationComponentSpec}
|
||||
* implementation for the {@link org.springframework.kafka.core.KafkaTemplate}.
|
||||
*
|
||||
* @param <K> the key type.
|
||||
* @param <V> the request value type.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2019 the original author or authors.
|
||||
* Copyright 2018-2020 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.
|
||||
@@ -19,7 +19,6 @@ package org.springframework.integration.kafka.dsl;
|
||||
import org.springframework.integration.dsl.IntegrationComponentSpec;
|
||||
import org.springframework.kafka.core.KafkaTemplate;
|
||||
import org.springframework.kafka.core.ProducerFactory;
|
||||
import org.springframework.kafka.support.LoggingProducerListener;
|
||||
import org.springframework.kafka.support.ProducerListener;
|
||||
import org.springframework.kafka.support.converter.RecordMessageConverter;
|
||||
|
||||
@@ -68,7 +67,7 @@ public class KafkaTemplateSpec<K, V>
|
||||
|
||||
/**
|
||||
* Set a {@link ProducerListener} which will be invoked when Kafka acknowledges
|
||||
* a send operation. By default a {@link LoggingProducerListener} is configured
|
||||
* a send operation. By default a {@link org.springframework.kafka.support.LoggingProducerListener} is configured
|
||||
* which logs errors only.
|
||||
* @param producerListener the listener; may be {@code null}.
|
||||
* @return the spec
|
||||
|
||||
@@ -72,7 +72,7 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class KafkaInboundGateway<K, V, R> extends MessagingGatewaySupport implements OrderlyShutdownCapable {
|
||||
|
||||
private static final ThreadLocal<AttributeAccessor> attributesHolder = new ThreadLocal<>();
|
||||
private static final ThreadLocal<AttributeAccessor> ATTRIBUTES_HOLDER = new ThreadLocal<>();
|
||||
|
||||
private final IntegrationRecordMessageListener listener = new IntegrationRecordMessageListener();
|
||||
|
||||
@@ -82,7 +82,7 @@ public class KafkaInboundGateway<K, V, R> extends MessagingGatewaySupport implem
|
||||
|
||||
private RetryTemplate retryTemplate;
|
||||
|
||||
private RecoveryCallback<? extends Object> recoveryCallback;
|
||||
private RecoveryCallback<?> recoveryCallback;
|
||||
|
||||
private BiConsumer<Map<TopicPartition, Long>, ConsumerSeekAware.ConsumerSeekCallback> onPartitionsAssignedSeekCallback;
|
||||
|
||||
@@ -143,7 +143,7 @@ public class KafkaInboundGateway<K, V, R> extends MessagingGatewaySupport implem
|
||||
* Does not make sense if {@link #setRetryTemplate(RetryTemplate)} isn't specified.
|
||||
* @param recoveryCallback the recovery callback.
|
||||
*/
|
||||
public void setRecoveryCallback(RecoveryCallback<? extends Object> recoveryCallback) {
|
||||
public void setRecoveryCallback(RecoveryCallback<?> recoveryCallback) {
|
||||
this.recoveryCallback = recoveryCallback;
|
||||
}
|
||||
|
||||
@@ -224,10 +224,10 @@ public class KafkaInboundGateway<K, V, R> extends MessagingGatewaySupport implem
|
||||
boolean needHolder = getErrorChannel() != null && this.retryTemplate == null;
|
||||
boolean needAttributes = needHolder | this.retryTemplate != null;
|
||||
if (needHolder) {
|
||||
attributesHolder.set(ErrorMessageUtils.getAttributeAccessor(null, null));
|
||||
ATTRIBUTES_HOLDER.set(ErrorMessageUtils.getAttributeAccessor(null, null));
|
||||
}
|
||||
if (needAttributes) {
|
||||
AttributeAccessor attributes = attributesHolder.get();
|
||||
AttributeAccessor attributes = ATTRIBUTES_HOLDER.get();
|
||||
if (attributes != null) {
|
||||
attributes.setAttribute(ErrorMessageUtils.INPUT_MESSAGE_CONTEXT_KEY, message);
|
||||
attributes.setAttribute(KafkaHeaders.RAW_DATA, record);
|
||||
@@ -237,7 +237,7 @@ public class KafkaInboundGateway<K, V, R> extends MessagingGatewaySupport implem
|
||||
|
||||
@Override
|
||||
protected AttributeAccessor getErrorMessageAttributes(Message<?> message) {
|
||||
AttributeAccessor attributes = attributesHolder.get();
|
||||
AttributeAccessor attributes = ATTRIBUTES_HOLDER.get();
|
||||
if (attributes == null) {
|
||||
return super.getErrorMessageAttributes(message);
|
||||
}
|
||||
@@ -283,7 +283,7 @@ public class KafkaInboundGateway<K, V, R> extends MessagingGatewaySupport implem
|
||||
}
|
||||
finally {
|
||||
if (KafkaInboundGateway.this.retryTemplate == null) {
|
||||
attributesHolder.remove();
|
||||
ATTRIBUTES_HOLDER.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -298,7 +298,7 @@ public class KafkaInboundGateway<K, V, R> extends MessagingGatewaySupport implem
|
||||
Map<String, Object> rawHeaders = ((KafkaMessageHeaders) message.getHeaders()).getRawHeaders();
|
||||
if (KafkaInboundGateway.this.retryTemplate != null) {
|
||||
AtomicInteger deliveryAttempt =
|
||||
new AtomicInteger(((RetryContext) attributesHolder.get()).getRetryCount() + 1);
|
||||
new AtomicInteger(((RetryContext) ATTRIBUTES_HOLDER.get()).getRetryCount() + 1);
|
||||
rawHeaders.put(IntegrationMessageHeaderAccessor.DELIVERY_ATTEMPT, deliveryAttempt);
|
||||
}
|
||||
else if (KafkaInboundGateway.this.containerDeliveryAttemptPresent) {
|
||||
@@ -314,7 +314,7 @@ public class KafkaInboundGateway<K, V, R> extends MessagingGatewaySupport implem
|
||||
MessageBuilder<?> builder = MessageBuilder.fromMessage(message);
|
||||
if (KafkaInboundGateway.this.retryTemplate != null) {
|
||||
AtomicInteger deliveryAttempt =
|
||||
new AtomicInteger(((RetryContext) attributesHolder.get()).getRetryCount() + 1);
|
||||
new AtomicInteger(((RetryContext) ATTRIBUTES_HOLDER.get()).getRetryCount() + 1);
|
||||
builder.setHeader(IntegrationMessageHeaderAccessor.DELIVERY_ATTEMPT, deliveryAttempt);
|
||||
}
|
||||
else if (KafkaInboundGateway.this.containerDeliveryAttemptPresent) {
|
||||
@@ -362,7 +362,7 @@ public class KafkaInboundGateway<K, V, R> extends MessagingGatewaySupport implem
|
||||
@Override
|
||||
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
|
||||
if (KafkaInboundGateway.this.retryTemplate != null) {
|
||||
attributesHolder.set(context);
|
||||
ATTRIBUTES_HOLDER.set(context);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -371,7 +371,7 @@ public class KafkaInboundGateway<K, V, R> extends MessagingGatewaySupport implem
|
||||
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback,
|
||||
Throwable throwable) {
|
||||
|
||||
attributesHolder.remove();
|
||||
ATTRIBUTES_HOLDER.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -33,7 +33,6 @@ import org.springframework.integration.context.OrderlyShutdownCapable;
|
||||
import org.springframework.integration.core.Pausable;
|
||||
import org.springframework.integration.endpoint.MessageProducerSupport;
|
||||
import org.springframework.integration.kafka.support.RawRecordHeaderErrorMessageStrategy;
|
||||
import org.springframework.integration.support.ErrorMessageStrategy;
|
||||
import org.springframework.integration.support.ErrorMessageUtils;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.kafka.listener.AbstractMessageListenerContainer;
|
||||
@@ -54,6 +53,7 @@ import org.springframework.kafka.support.converter.KafkaMessageHeaders;
|
||||
import org.springframework.kafka.support.converter.MessageConverter;
|
||||
import org.springframework.kafka.support.converter.RecordMessageConverter;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.support.ErrorMessage;
|
||||
import org.springframework.retry.RecoveryCallback;
|
||||
import org.springframework.retry.RetryCallback;
|
||||
@@ -78,7 +78,7 @@ import org.springframework.util.Assert;
|
||||
public class KafkaMessageDrivenChannelAdapter<K, V> extends MessageProducerSupport implements OrderlyShutdownCapable,
|
||||
Pausable {
|
||||
|
||||
private static final ThreadLocal<AttributeAccessor> attributesHolder = new ThreadLocal<>();
|
||||
private static final ThreadLocal<AttributeAccessor> ATTRIBUTES_HOLDER = new ThreadLocal<>();
|
||||
|
||||
private final AbstractMessageListenerContainer<K, V> messageListenerContainer;
|
||||
|
||||
@@ -354,7 +354,7 @@ public class KafkaMessageDrivenChannelAdapter<K, V> extends MessageProducerSuppo
|
||||
* If there's a retry template, it will set the attributes holder via the listener. If
|
||||
* there's no retry template, but there's an error channel, we create a new attributes
|
||||
* holder here. If an attributes holder exists (by either method), we set the
|
||||
* attributes for use by the {@link ErrorMessageStrategy}.
|
||||
* attributes for use by the {@link org.springframework.integration.support.ErrorMessageStrategy}.
|
||||
* @param record the record.
|
||||
* @param message the message.
|
||||
* @since 2.1.1
|
||||
@@ -363,10 +363,10 @@ public class KafkaMessageDrivenChannelAdapter<K, V> extends MessageProducerSuppo
|
||||
boolean needHolder = getErrorChannel() != null && this.retryTemplate == null;
|
||||
boolean needAttributes = needHolder | this.retryTemplate != null;
|
||||
if (needHolder) {
|
||||
attributesHolder.set(ErrorMessageUtils.getAttributeAccessor(null, null));
|
||||
ATTRIBUTES_HOLDER.set(ErrorMessageUtils.getAttributeAccessor(null, null));
|
||||
}
|
||||
if (needAttributes) {
|
||||
AttributeAccessor attributes = attributesHolder.get();
|
||||
AttributeAccessor attributes = ATTRIBUTES_HOLDER.get();
|
||||
if (attributes != null) {
|
||||
attributes.setAttribute(ErrorMessageUtils.INPUT_MESSAGE_CONTEXT_KEY, message);
|
||||
attributes.setAttribute(KafkaHeaders.RAW_DATA, record);
|
||||
@@ -376,7 +376,7 @@ public class KafkaMessageDrivenChannelAdapter<K, V> extends MessageProducerSuppo
|
||||
|
||||
@Override
|
||||
protected AttributeAccessor getErrorMessageAttributes(Message<?> message) {
|
||||
AttributeAccessor attributes = attributesHolder.get();
|
||||
AttributeAccessor attributes = ATTRIBUTES_HOLDER.get();
|
||||
if (attributes == null) {
|
||||
return super.getErrorMessageAttributes(message);
|
||||
}
|
||||
@@ -392,7 +392,7 @@ public class KafkaMessageDrivenChannelAdapter<K, V> extends MessageProducerSuppo
|
||||
}
|
||||
finally {
|
||||
if (KafkaMessageDrivenChannelAdapter.this.retryTemplate == null) {
|
||||
attributesHolder.remove();
|
||||
ATTRIBUTES_HOLDER.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -456,7 +456,7 @@ public class KafkaMessageDrivenChannelAdapter<K, V> extends MessageProducerSuppo
|
||||
Map<String, Object> rawHeaders = ((KafkaMessageHeaders) message.getHeaders()).getRawHeaders();
|
||||
if (KafkaMessageDrivenChannelAdapter.this.retryTemplate != null) {
|
||||
AtomicInteger deliveryAttempt =
|
||||
new AtomicInteger(((RetryContext) attributesHolder.get()).getRetryCount() + 1);
|
||||
new AtomicInteger(((RetryContext) ATTRIBUTES_HOLDER.get()).getRetryCount() + 1);
|
||||
rawHeaders.put(IntegrationMessageHeaderAccessor.DELIVERY_ATTEMPT, deliveryAttempt);
|
||||
}
|
||||
else if (KafkaMessageDrivenChannelAdapter.this.containerDeliveryAttemptPresent) {
|
||||
@@ -472,7 +472,7 @@ public class KafkaMessageDrivenChannelAdapter<K, V> extends MessageProducerSuppo
|
||||
MessageBuilder<?> builder = MessageBuilder.fromMessage(message);
|
||||
if (KafkaMessageDrivenChannelAdapter.this.retryTemplate != null) {
|
||||
AtomicInteger deliveryAttempt =
|
||||
new AtomicInteger(((RetryContext) attributesHolder.get()).getRetryCount() + 1);
|
||||
new AtomicInteger(((RetryContext) ATTRIBUTES_HOLDER.get()).getRetryCount() + 1);
|
||||
builder.setHeader(IntegrationMessageHeaderAccessor.DELIVERY_ATTEMPT, deliveryAttempt);
|
||||
}
|
||||
else if (KafkaMessageDrivenChannelAdapter.this.containerDeliveryAttemptPresent) {
|
||||
@@ -491,7 +491,7 @@ public class KafkaMessageDrivenChannelAdapter<K, V> extends MessageProducerSuppo
|
||||
@Override
|
||||
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
|
||||
if (KafkaMessageDrivenChannelAdapter.this.retryTemplate != null) {
|
||||
attributesHolder.set(context);
|
||||
ATTRIBUTES_HOLDER.set(context);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -500,7 +500,7 @@ public class KafkaMessageDrivenChannelAdapter<K, V> extends MessageProducerSuppo
|
||||
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback,
|
||||
Throwable throwable) {
|
||||
|
||||
attributesHolder.remove();
|
||||
ATTRIBUTES_HOLDER.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -536,8 +536,9 @@ public class KafkaMessageDrivenChannelAdapter<K, V> extends MessageProducerSuppo
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
Exception exception = new ConversionException("Failed to convert to message for: " + records, e);
|
||||
if (getErrorChannel() != null) {
|
||||
getMessagingTemplate().send(getErrorChannel(), new ErrorMessage(exception));
|
||||
MessageChannel errorChannel = getErrorChannel();
|
||||
if (errorChannel != null) {
|
||||
getMessagingTemplate().send(errorChannel, new ErrorMessage(exception));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -547,7 +548,7 @@ public class KafkaMessageDrivenChannelAdapter<K, V> extends MessageProducerSuppo
|
||||
@Override
|
||||
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
|
||||
if (KafkaMessageDrivenChannelAdapter.this.retryTemplate != null) {
|
||||
attributesHolder.set(context);
|
||||
ATTRIBUTES_HOLDER.set(context);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -556,7 +557,7 @@ public class KafkaMessageDrivenChannelAdapter<K, V> extends MessageProducerSuppo
|
||||
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback,
|
||||
Throwable throwable) {
|
||||
|
||||
attributesHolder.remove();
|
||||
ATTRIBUTES_HOLDER.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -30,7 +30,7 @@ import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -107,9 +107,6 @@ public class KafkaMessageSource<K, V> extends AbstractMessageSource<Object> impl
|
||||
*/
|
||||
public static final String REMAINING_RECORDS = KafkaHeaders.PREFIX + "remainingRecords";
|
||||
|
||||
private final Supplier<Duration> minTimeoutProvider =
|
||||
() -> Duration.ofMillis(Math.max(this.pollTimeout.toMillis() * 20, MIN_ASSIGN_TIMEOUT));
|
||||
|
||||
private final ConsumerFactory<K, V> consumerFactory;
|
||||
|
||||
private final KafkaAckCallbackFactory<K, V> ackCallbackFactory;
|
||||
@@ -124,7 +121,11 @@ public class KafkaMessageSource<K, V> extends AbstractMessageSource<Object> impl
|
||||
|
||||
private final Collection<TopicPartition> assignedPartitions = new LinkedHashSet<>();
|
||||
|
||||
private Duration pollTimeout;
|
||||
private final Duration commitTimeout;
|
||||
|
||||
private final Duration assignTimeout;
|
||||
|
||||
private final Duration pollTimeout;
|
||||
|
||||
private RecordMessageConverter messageConverter = new MessagingMessageConverter();
|
||||
|
||||
@@ -132,12 +133,8 @@ public class KafkaMessageSource<K, V> extends AbstractMessageSource<Object> impl
|
||||
|
||||
private boolean rawMessageHeader;
|
||||
|
||||
private Duration commitTimeout;
|
||||
|
||||
private boolean running;
|
||||
|
||||
private Duration assignTimeout;
|
||||
|
||||
private volatile Consumer<K, V> consumer;
|
||||
|
||||
private volatile boolean pausing;
|
||||
@@ -231,7 +228,8 @@ public class KafkaMessageSource<K, V> extends AbstractMessageSource<Object> impl
|
||||
this.consumerFactory = fixOrRejectConsumerFactory(consumerFactory, allowMultiFetch);
|
||||
this.ackCallbackFactory = ackCallbackFactory;
|
||||
this.pollTimeout = Duration.ofMillis(consumerProperties.getPollTimeout());
|
||||
this.assignTimeout = this.minTimeoutProvider.get();
|
||||
this.assignTimeout =
|
||||
Duration.ofMillis(Math.max(this.pollTimeout.toMillis() * 20, MIN_ASSIGN_TIMEOUT)); // NOSONAR - magic
|
||||
this.commitTimeout = consumerProperties.getSyncCommitTimeout();
|
||||
}
|
||||
|
||||
@@ -431,7 +429,6 @@ public class KafkaMessageSource<K, V> extends AbstractMessageSource<Object> impl
|
||||
this.logger.debug("Consumer is paused; no records will be returned");
|
||||
}
|
||||
ConsumerRecord<K, V> record;
|
||||
TopicPartition topicPartition;
|
||||
if (this.recordsIterator != null) {
|
||||
record = nextRecord();
|
||||
}
|
||||
@@ -447,125 +444,30 @@ public class KafkaMessageSource<K, V> extends AbstractMessageSource<Object> impl
|
||||
record = nextRecord();
|
||||
}
|
||||
}
|
||||
topicPartition = new TopicPartition(record.topic(), record.partition());
|
||||
KafkaAckInfo<K, V> ackInfo = new KafkaAckInfoImpl(record, topicPartition);
|
||||
AcknowledgmentCallback ackCallback = this.ackCallbackFactory.createCallback(ackInfo);
|
||||
this.inflightRecords.computeIfAbsent(topicPartition, tp -> Collections.synchronizedSet(new TreeSet<>()))
|
||||
.add(ackInfo);
|
||||
Message<?> message = this.messageConverter.toMessage(record,
|
||||
ackCallback instanceof Acknowledgment ? (Acknowledgment) ackCallback : null, this.consumer,
|
||||
this.payloadType);
|
||||
if (message.getHeaders() instanceof KafkaMessageHeaders) {
|
||||
Map<String, Object> rawHeaders = ((KafkaMessageHeaders) message.getHeaders()).getRawHeaders();
|
||||
rawHeaders.put(IntegrationMessageHeaderAccessor.ACKNOWLEDGMENT_CALLBACK, ackCallback);
|
||||
rawHeaders.put(REMAINING_RECORDS, this.remainingCount.get());
|
||||
if (this.rawMessageHeader) {
|
||||
rawHeaders.put(KafkaHeaders.RAW_DATA, record);
|
||||
rawHeaders.put(IntegrationMessageHeaderAccessor.SOURCE_DATA, record);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
else {
|
||||
AbstractIntegrationMessageBuilder<?> builder = getMessageBuilderFactory().fromMessage(message)
|
||||
.setHeader(IntegrationMessageHeaderAccessor.ACKNOWLEDGMENT_CALLBACK, ackCallback)
|
||||
.setHeader(REMAINING_RECORDS, this.remainingCount.get());
|
||||
if (this.rawMessageHeader) {
|
||||
builder.setHeader(KafkaHeaders.RAW_DATA, record);
|
||||
builder.setHeader(IntegrationMessageHeaderAccessor.SOURCE_DATA, record);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
private ConsumerRecord<K, V> nextRecord() {
|
||||
ConsumerRecord<K, V> record;
|
||||
record = this.recordsIterator.next();
|
||||
if (!this.recordsIterator.hasNext()) {
|
||||
this.recordsIterator = null;
|
||||
}
|
||||
this.remainingCount.decrementAndGet();
|
||||
return record;
|
||||
return recordToMessage(record);
|
||||
}
|
||||
|
||||
protected void createConsumer() {
|
||||
synchronized (this.consumerMonitor) {
|
||||
this.consumer = this.consumerFactory.createConsumer(this.consumerProperties.getGroupId(),
|
||||
this.consumerProperties.getClientId(), null, this.consumerProperties.getKafkaConsumerProperties());
|
||||
ConsumerRebalanceListener providedRebalanceListener = this.consumerProperties
|
||||
.getConsumerRebalanceListener();
|
||||
boolean isConsumerAware = providedRebalanceListener instanceof ConsumerAwareRebalanceListener;
|
||||
ConsumerRebalanceListener rebalanceCallback = new ConsumerRebalanceListener() {
|
||||
|
||||
@Override
|
||||
public void onPartitionsRevoked(Collection<TopicPartition> partitions) {
|
||||
KafkaMessageSource.this.assignedPartitions.removeAll(partitions);
|
||||
if (KafkaMessageSource.this.logger.isInfoEnabled()) {
|
||||
KafkaMessageSource.this.logger
|
||||
.info("Partitions revoked: " + partitions);
|
||||
}
|
||||
if (providedRebalanceListener != null) {
|
||||
if (isConsumerAware) {
|
||||
((ConsumerAwareRebalanceListener) providedRebalanceListener)
|
||||
.onPartitionsRevokedAfterCommit(KafkaMessageSource.this.consumer, partitions);
|
||||
}
|
||||
else {
|
||||
providedRebalanceListener.onPartitionsRevoked(partitions);
|
||||
}
|
||||
}
|
||||
ConsumerRebalanceListener rebalanceCallback =
|
||||
new ItegrationConsumerRebalanceListener(this.consumerProperties.getConsumerRebalanceListener());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPartitionsLost(Collection<TopicPartition> partitions) {
|
||||
if (providedRebalanceListener != null) {
|
||||
if (isConsumerAware) {
|
||||
((ConsumerAwareRebalanceListener) providedRebalanceListener).onPartitionsLost(partitions);
|
||||
}
|
||||
else {
|
||||
providedRebalanceListener.onPartitionsLost(partitions);
|
||||
}
|
||||
}
|
||||
onPartitionsRevoked(partitions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPartitionsAssigned(Collection<TopicPartition> partitions) {
|
||||
KafkaMessageSource.this.assignedPartitions.addAll(partitions);
|
||||
if (KafkaMessageSource.this.paused) {
|
||||
KafkaMessageSource.this.consumer.pause(KafkaMessageSource.this.assignedPartitions);
|
||||
KafkaMessageSource.this.logger.warn("Paused consumer resumed by Kafka due to rebalance; "
|
||||
+ "consumer paused again, so the initial poll() will never return any records");
|
||||
}
|
||||
if (KafkaMessageSource.this.logger.isInfoEnabled()) {
|
||||
KafkaMessageSource.this.logger
|
||||
.info("Partitions assigned: " + partitions);
|
||||
}
|
||||
if (providedRebalanceListener != null) {
|
||||
if (isConsumerAware) {
|
||||
((ConsumerAwareRebalanceListener) providedRebalanceListener)
|
||||
.onPartitionsAssigned(KafkaMessageSource.this.consumer, partitions);
|
||||
}
|
||||
else {
|
||||
providedRebalanceListener.onPartitionsAssigned(partitions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
if (this.consumerProperties.getTopicPattern() != null) {
|
||||
this.consumer.subscribe(this.consumerProperties.getTopicPattern(), rebalanceCallback);
|
||||
Pattern topicPattern = this.consumerProperties.getTopicPattern();
|
||||
TopicPartitionOffset[] partitions = this.consumerProperties.getTopicPartitions();
|
||||
if (topicPattern != null) {
|
||||
this.consumer.subscribe(topicPattern, rebalanceCallback);
|
||||
}
|
||||
else if (this.consumerProperties.getTopicPartitions() != null) {
|
||||
List<TopicPartition> topicPartitionsToAssign = Arrays
|
||||
.stream(this.consumerProperties.getTopicPartitions())
|
||||
.map(TopicPartitionOffset::getTopicPartition)
|
||||
.collect(Collectors.toList());
|
||||
else if (partitions != null) {
|
||||
List<TopicPartition> topicPartitionsToAssign =
|
||||
Arrays.stream(partitions)
|
||||
.map(TopicPartitionOffset::getTopicPartition)
|
||||
.collect(Collectors.toList());
|
||||
this.consumer.assign(topicPartitionsToAssign);
|
||||
this.assignedPartitions.addAll(topicPartitionsToAssign);
|
||||
|
||||
TopicPartitionOffset[] partitions = this.consumerProperties.getTopicPartitions();
|
||||
|
||||
for (TopicPartitionOffset partition : partitions) {
|
||||
if (TopicPartitionOffset.SeekPosition.BEGINNING.equals(partition.getPosition())) {
|
||||
this.consumer.seekToBeginning(Collections.singleton(partition.getTopicPartition()));
|
||||
@@ -603,11 +505,53 @@ public class KafkaMessageSource<K, V> extends AbstractMessageSource<Object> impl
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.consumer.subscribe(Arrays.asList(this.consumerProperties.getTopics()), rebalanceCallback);
|
||||
this.consumer.subscribe(Arrays.asList(this.consumerProperties.getTopics()), // NOSONAR
|
||||
rebalanceCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ConsumerRecord<K, V> nextRecord() {
|
||||
ConsumerRecord<K, V> record;
|
||||
record = this.recordsIterator.next();
|
||||
if (!this.recordsIterator.hasNext()) {
|
||||
this.recordsIterator = null;
|
||||
}
|
||||
this.remainingCount.decrementAndGet();
|
||||
return record;
|
||||
}
|
||||
|
||||
private Object recordToMessage(ConsumerRecord<K, V> record) {
|
||||
TopicPartition topicPartition = new TopicPartition(record.topic(), record.partition());
|
||||
KafkaAckInfo<K, V> ackInfo = new KafkaAckInfoImpl(record, topicPartition);
|
||||
AcknowledgmentCallback ackCallback = this.ackCallbackFactory.createCallback(ackInfo);
|
||||
this.inflightRecords.computeIfAbsent(topicPartition, tp -> Collections.synchronizedSet(new TreeSet<>()))
|
||||
.add(ackInfo);
|
||||
Message<?> message = this.messageConverter.toMessage(record,
|
||||
ackCallback instanceof Acknowledgment ? (Acknowledgment) ackCallback : null, this.consumer,
|
||||
this.payloadType);
|
||||
if (message.getHeaders() instanceof KafkaMessageHeaders) {
|
||||
Map<String, Object> rawHeaders = ((KafkaMessageHeaders) message.getHeaders()).getRawHeaders();
|
||||
rawHeaders.put(IntegrationMessageHeaderAccessor.ACKNOWLEDGMENT_CALLBACK, ackCallback);
|
||||
rawHeaders.put(REMAINING_RECORDS, this.remainingCount.get());
|
||||
if (this.rawMessageHeader) {
|
||||
rawHeaders.put(KafkaHeaders.RAW_DATA, record);
|
||||
rawHeaders.put(IntegrationMessageHeaderAccessor.SOURCE_DATA, record);
|
||||
}
|
||||
return message;
|
||||
}
|
||||
else {
|
||||
AbstractIntegrationMessageBuilder<?> builder = getMessageBuilderFactory().fromMessage(message)
|
||||
.setHeader(IntegrationMessageHeaderAccessor.ACKNOWLEDGMENT_CALLBACK, ackCallback)
|
||||
.setHeader(REMAINING_RECORDS, this.remainingCount.get());
|
||||
if (this.rawMessageHeader) {
|
||||
builder.setHeader(KafkaHeaders.RAW_DATA, record);
|
||||
builder.setHeader(IntegrationMessageHeaderAccessor.SOURCE_DATA, record);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void destroy() {
|
||||
stopConsumer();
|
||||
@@ -623,6 +567,67 @@ public class KafkaMessageSource<K, V> extends AbstractMessageSource<Object> impl
|
||||
}
|
||||
}
|
||||
|
||||
private class ItegrationConsumerRebalanceListener implements ConsumerRebalanceListener {
|
||||
|
||||
private final ConsumerRebalanceListener providedRebalanceListener;
|
||||
|
||||
private final boolean isConsumerAware;
|
||||
|
||||
ItegrationConsumerRebalanceListener(ConsumerRebalanceListener providedRebalanceListener) {
|
||||
this.providedRebalanceListener = providedRebalanceListener;
|
||||
this.isConsumerAware = providedRebalanceListener instanceof ConsumerAwareRebalanceListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPartitionsRevoked(Collection<TopicPartition> partitions) {
|
||||
KafkaMessageSource.this.assignedPartitions.removeAll(partitions);
|
||||
if (KafkaMessageSource.this.logger.isInfoEnabled()) {
|
||||
KafkaMessageSource.this.logger.info("Partitions revoked: " + partitions);
|
||||
}
|
||||
if (this.providedRebalanceListener != null) {
|
||||
if (this.isConsumerAware) {
|
||||
((ConsumerAwareRebalanceListener) this.providedRebalanceListener)
|
||||
.onPartitionsRevokedAfterCommit(KafkaMessageSource.this.consumer, partitions);
|
||||
}
|
||||
else {
|
||||
this.providedRebalanceListener.onPartitionsRevoked(partitions);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPartitionsLost(Collection<TopicPartition> partitions) {
|
||||
if (this.providedRebalanceListener != null) {
|
||||
this.providedRebalanceListener.onPartitionsLost(partitions);
|
||||
}
|
||||
onPartitionsRevoked(partitions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPartitionsAssigned(Collection<TopicPartition> partitions) {
|
||||
KafkaMessageSource.this.assignedPartitions.addAll(partitions);
|
||||
if (KafkaMessageSource.this.paused) {
|
||||
KafkaMessageSource.this.consumer.pause(KafkaMessageSource.this.assignedPartitions);
|
||||
KafkaMessageSource.this.logger.warn("Paused consumer resumed by Kafka due to rebalance; "
|
||||
+ "consumer paused again, so the initial poll() will never return any records");
|
||||
}
|
||||
if (KafkaMessageSource.this.logger.isInfoEnabled()) {
|
||||
KafkaMessageSource.this.logger.info("Partitions assigned: " + partitions);
|
||||
}
|
||||
if (this.providedRebalanceListener != null) {
|
||||
if (this.isConsumerAware) {
|
||||
((ConsumerAwareRebalanceListener) this.providedRebalanceListener)
|
||||
.onPartitionsAssigned(KafkaMessageSource.this.consumer, partitions);
|
||||
}
|
||||
else {
|
||||
this.providedRebalanceListener.onPartitionsAssigned(partitions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* AcknowledgmentCallbackFactory for KafkaAckInfo.
|
||||
* @param <K> the key type.
|
||||
@@ -693,7 +698,7 @@ public class KafkaMessageSource<K, V> extends AbstractMessageSource<Object> impl
|
||||
consumerProperties != null
|
||||
? consumerProperties.getCommitLogLevel()
|
||||
: LogIfLevelEnabled.Level.DEBUG);
|
||||
this.logOnlyMetadata = consumerProperties.isOnlyLogRecordMetadata();
|
||||
this.logOnlyMetadata = consumerProperties != null && consumerProperties.isOnlyLogRecordMetadata();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -751,7 +756,7 @@ public class KafkaMessageSource<K, V> extends AbstractMessageSource<Object> impl
|
||||
}
|
||||
}
|
||||
|
||||
private void commitIfPossible(ConsumerRecord<K, V> record) {
|
||||
private void commitIfPossible(ConsumerRecord<K, V> record) { // NOSONAR
|
||||
if (this.ackInfo.isRolledBack()) {
|
||||
if (this.logger.isWarnEnabled()) {
|
||||
this.logger.warn("Cannot commit offset for "
|
||||
@@ -783,7 +788,7 @@ public class KafkaMessageSource<K, V> extends AbstractMessageSource<Object> impl
|
||||
+ ListenerUtils.recordToString(record, this.logOnlyMetadata)
|
||||
+ " and all deferred to "
|
||||
+ ListenerUtils.recordToString(ackInformationToLog.getRecord(),
|
||||
this.logOnlyMetadata));
|
||||
this.logOnlyMetadata));
|
||||
candidates.removeAll(toCommit);
|
||||
}
|
||||
else {
|
||||
@@ -845,7 +850,7 @@ public class KafkaMessageSource<K, V> extends AbstractMessageSource<Object> impl
|
||||
/**
|
||||
* Information for building an KafkaAckCallback.
|
||||
*/
|
||||
public class KafkaAckInfoImpl implements KafkaAckInfo<K, V> {
|
||||
public class KafkaAckInfoImpl implements KafkaAckInfo<K, V> { // NOSONAR - no equals() impl
|
||||
|
||||
private final ConsumerRecord<K, V> record;
|
||||
|
||||
|
||||
@@ -66,7 +66,6 @@ import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.MessageHandlingException;
|
||||
import org.springframework.messaging.MessageHeaders;
|
||||
import org.springframework.messaging.support.ErrorMessage;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -151,7 +150,7 @@ public class KafkaProducerMessageHandler<K, V> extends AbstractReplyProducingMes
|
||||
|
||||
private ProducerRecordCreator<K, V> producerRecordCreator =
|
||||
(message, topic, partition, timestamp, key, value, headers) ->
|
||||
new ProducerRecord<>(topic, partition, timestamp, key, value, headers);
|
||||
new ProducerRecord<>(topic, partition, timestamp, key, value, headers);
|
||||
|
||||
private volatile byte[] singleReplyTopic;
|
||||
|
||||
@@ -162,7 +161,7 @@ public class KafkaProducerMessageHandler<K, V> extends AbstractReplyProducingMes
|
||||
if (this.isGateway) {
|
||||
setAsync(true);
|
||||
updateNotPropagatedHeaders(
|
||||
new String[] { KafkaHeaders.TOPIC, KafkaHeaders.PARTITION_ID, KafkaHeaders.MESSAGE_KEY }, false);
|
||||
new String[]{KafkaHeaders.TOPIC, KafkaHeaders.PARTITION_ID, KafkaHeaders.MESSAGE_KEY}, false);
|
||||
}
|
||||
if (JacksonPresent.isJackson2Present()) {
|
||||
this.headerMapper = new DefaultKafkaHeaderMapper();
|
||||
@@ -270,7 +269,8 @@ public class KafkaProducerMessageHandler<K, V> extends AbstractReplyProducingMes
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the failure channel. After a send failure, an {@link ErrorMessage} will be sent
|
||||
* Set the failure channel. After a send failure, an
|
||||
* {@link org.springframework.messaging.support.ErrorMessage} will be sent
|
||||
* to this channel with a payload of a {@link KafkaSendFailureException} with the
|
||||
* failed message and cause.
|
||||
* @param sendFailureChannel the failure channel.
|
||||
@@ -281,7 +281,8 @@ public class KafkaProducerMessageHandler<K, V> extends AbstractReplyProducingMes
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the failure channel name. After a send failure, an {@link ErrorMessage} will be
|
||||
* Set the failure channel name. After a send failure, an
|
||||
* {@link org.springframework.messaging.support.ErrorMessage} will be
|
||||
* sent to this channel name with a payload of a {@link KafkaSendFailureException}
|
||||
* with the failed message and cause.
|
||||
* @param sendFailureChannelName the failure channel name.
|
||||
@@ -392,10 +393,8 @@ public class KafkaProducerMessageHandler<K, V> extends AbstractReplyProducingMes
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
if (this.running.compareAndSet(true, false)) {
|
||||
if (!this.transactional || this.allowNonTransactional) {
|
||||
this.kafkaTemplate.flush();
|
||||
}
|
||||
if (this.running.compareAndSet(true, false) && (!this.transactional || this.allowNonTransactional)) {
|
||||
this.kafkaTemplate.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,11 +403,12 @@ public class KafkaProducerMessageHandler<K, V> extends AbstractReplyProducingMes
|
||||
return this.running.get();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings("unchecked") // NOSONAR - complexity
|
||||
@Override
|
||||
protected Object handleRequestMessage(final Message<?> message) {
|
||||
final ProducerRecord<K, V> producerRecord;
|
||||
boolean flush = this.flushExpression.getValue(this.evaluationContext, message, Boolean.class);
|
||||
boolean flush =
|
||||
Boolean.TRUE.equals(this.flushExpression.getValue(this.evaluationContext, message, Boolean.class));
|
||||
boolean preBuilt = message.getPayload() instanceof ProducerRecord;
|
||||
if (preBuilt) {
|
||||
producerRecord = (ProducerRecord<K, V>) message.getPayload();
|
||||
@@ -430,9 +430,7 @@ public class KafkaProducerMessageHandler<K, V> extends AbstractReplyProducingMes
|
||||
if (this.transactional
|
||||
&& TransactionSynchronizationManager.getResource(this.kafkaTemplate.getProducerFactory()) == null
|
||||
&& !this.allowNonTransactional) {
|
||||
sendFuture = this.kafkaTemplate.executeInTransaction(template -> {
|
||||
return template.send(producerRecord);
|
||||
});
|
||||
sendFuture = this.kafkaTemplate.executeInTransaction(template -> template.send(producerRecord));
|
||||
}
|
||||
else {
|
||||
sendFuture = this.kafkaTemplate.send(producerRecord);
|
||||
@@ -446,7 +444,7 @@ public class KafkaProducerMessageHandler<K, V> extends AbstractReplyProducingMes
|
||||
throw new MessageHandlingException(message, e);
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
throw new MessageHandlingException(message, e.getCause());
|
||||
throw new MessageHandlingException(message, e.getCause()); // NOSONAR
|
||||
}
|
||||
if (flush) {
|
||||
this.kafkaTemplate.flush();
|
||||
@@ -488,12 +486,11 @@ public class KafkaProducerMessageHandler<K, V> extends AbstractReplyProducingMes
|
||||
headers = new RecordHeaders();
|
||||
this.headerMapper.fromHeaders(messageHeaders, headers);
|
||||
}
|
||||
final ProducerRecord<K, V> producerRecord = this.producerRecordCreator.create(message, topic, partitionId,
|
||||
timestamp, (K) messageKey, payload, headers);
|
||||
return producerRecord;
|
||||
return this.producerRecordCreator.create(message, topic, partitionId, timestamp, (K) messageKey, payload,
|
||||
headers);
|
||||
}
|
||||
|
||||
private byte[] getReplyTopic(final Message<?> message) {
|
||||
private byte[] getReplyTopic(Message<?> message) { // NOSONAR
|
||||
if (this.replyTopicsAndPartitions.isEmpty()) {
|
||||
determineValidReplyTopicsAndPartitions();
|
||||
}
|
||||
@@ -569,8 +566,9 @@ public class KafkaProducerMessageHandler<K, V> extends AbstractReplyProducingMes
|
||||
ListenableFuture<SendResult<K, V>> future, MessageChannel metadataChannel)
|
||||
throws InterruptedException, ExecutionException {
|
||||
|
||||
if (getSendFailureChannel() != null || metadataChannel != null) {
|
||||
future.addCallback(new ListenableFutureCallback<SendResult<K, V>>() {
|
||||
final MessageChannel sendFailureChannel = getSendFailureChannel();
|
||||
if (sendFailureChannel != null || metadataChannel != null) {
|
||||
future.addCallback(new ListenableFutureCallback<SendResult<K, V>>() { // NOSONAR
|
||||
|
||||
@Override
|
||||
public void onSuccess(SendResult<K, V> result) {
|
||||
@@ -583,8 +581,8 @@ public class KafkaProducerMessageHandler<K, V> extends AbstractReplyProducingMes
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
if (getSendFailureChannel() != null) {
|
||||
KafkaProducerMessageHandler.this.messagingTemplate.send(getSendFailureChannel(),
|
||||
if (sendFailureChannel != null) {
|
||||
KafkaProducerMessageHandler.this.messagingTemplate.send(sendFailureChannel,
|
||||
KafkaProducerMessageHandler.this.errorMessageStrategy.buildErrorMessage(
|
||||
new KafkaSendFailureException(message, producerRecord, ex), null));
|
||||
}
|
||||
@@ -623,7 +621,7 @@ public class KafkaProducerMessageHandler<K, V> extends AbstractReplyProducingMes
|
||||
}
|
||||
|
||||
private void addCallback(final RequestReplyFuture<?, ?, Object> future) {
|
||||
future.addCallback(new ListenableFutureCallback<ConsumerRecord<?, Object>>() {
|
||||
future.addCallback(new ListenableFutureCallback<ConsumerRecord<?, Object>>() { // NOSONAR
|
||||
|
||||
@Override
|
||||
public void onSuccess(ConsumerRecord<?, Object> result) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018-2019 the original author or authors.
|
||||
* Copyright 2018-2020 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.
|
||||
@@ -251,13 +251,13 @@ class MessageSourceTests {
|
||||
return null;
|
||||
}).given(consumer).commitAsync(any(), any());
|
||||
Map<TopicPartition, List<ConsumerRecord>> records1 = new LinkedHashMap<>();
|
||||
records1.put(topicPartition, Arrays.asList(
|
||||
records1.put(topicPartition, Collections.singletonList(
|
||||
new ConsumerRecord("foo", 0, 0L, 0L, TimestampType.NO_TIMESTAMP_TYPE, 0, 0, 0, null, "foo")));
|
||||
Map<TopicPartition, List<ConsumerRecord>> records2 = new LinkedHashMap<>();
|
||||
records2.put(topicPartition, Arrays.asList(
|
||||
records2.put(topicPartition, Collections.singletonList(
|
||||
new ConsumerRecord("foo", 0, 1L, 0L, TimestampType.NO_TIMESTAMP_TYPE, 0, 0, 0, null, "bar")));
|
||||
Map<TopicPartition, List<ConsumerRecord>> records3 = new LinkedHashMap<>();
|
||||
records3.put(topicPartition, Arrays.asList(
|
||||
records3.put(topicPartition, Collections.singletonList(
|
||||
new ConsumerRecord("foo", 0, 2L, 0L, TimestampType.NO_TIMESTAMP_TYPE, 0, 0, 0, null, "baz")));
|
||||
Map<TopicPartition, List<ConsumerRecord>> records4 = new LinkedHashMap<>();
|
||||
records4.put(topicPartition, Collections.singletonList(
|
||||
|
||||
Reference in New Issue
Block a user