Skip to content

Commit 9994997

Browse files
garyrussellartembilan
authored andcommitted
GH-3067: Use default NullChannel instance if poss.
Resolves #3067 Also add missing receive counter. * Late binding of null discard channel; checkstyle * Fix test; fall back to new NullChannel(); always evaluate tx expressions
1 parent 0c7cae1 commit 9994997

File tree

8 files changed

+88
-43
lines changed

8 files changed

+88
-43
lines changed

spring-integration-core/src/main/java/org/springframework/integration/aggregator/AbstractCorrelatingMessageHandler.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.springframework.expression.Expression;
4040
import org.springframework.integration.IntegrationMessageHeaderAccessor;
4141
import org.springframework.integration.channel.NullChannel;
42+
import org.springframework.integration.context.IntegrationContextUtils;
4243
import org.springframework.integration.expression.ExpressionUtils;
4344
import org.springframework.integration.handler.AbstractMessageProducingHandler;
4445
import org.springframework.integration.handler.DiscardingMessageHandler;
@@ -55,6 +56,7 @@
5556
import org.springframework.messaging.MessageChannel;
5657
import org.springframework.messaging.MessageDeliveryException;
5758
import org.springframework.messaging.MessageHandlingException;
59+
import org.springframework.messaging.core.DestinationResolutionException;
5860
import org.springframework.util.Assert;
5961
import org.springframework.util.CollectionUtils;
6062

@@ -315,7 +317,7 @@ protected void onInit() {
315317
super.onInit();
316318
Assert.state(!(this.discardChannelName != null && this.discardChannel != null),
317319
"'discardChannelName' and 'discardChannel' are mutually exclusive.");
318-
BeanFactory beanFactory = this.getBeanFactory();
320+
BeanFactory beanFactory = getBeanFactory();
319321
if (beanFactory != null) {
320322
if (this.outputProcessor instanceof BeanFactoryAware) {
321323
((BeanFactoryAware) this.outputProcessor).setBeanFactory(beanFactory);
@@ -328,10 +330,6 @@ protected void onInit() {
328330
}
329331
}
330332

331-
if (this.discardChannel == null) {
332-
this.discardChannel = new NullChannel();
333-
}
334-
335333
if (this.releasePartialSequences) {
336334
Assert.isInstanceOf(SequenceSizeReleaseStrategy.class, this.releaseStrategy, () ->
337335
"Release strategy of type [" + this.releaseStrategy.getClass().getSimpleName() +
@@ -392,8 +390,21 @@ protected ReleaseStrategy getReleaseStrategy() {
392390
@Override
393391
public MessageChannel getDiscardChannel() {
394392
String channelName = this.discardChannelName;
393+
if (channelName == null && this.discardChannel == null) {
394+
channelName = IntegrationContextUtils.NULL_CHANNEL_BEAN_NAME;
395+
}
395396
if (channelName != null) {
396-
this.discardChannel = getChannelResolver().resolveDestination(channelName);
397+
try {
398+
this.discardChannel = getChannelResolver().resolveDestination(channelName);
399+
}
400+
catch (DestinationResolutionException ex) {
401+
if (channelName.equals(IntegrationContextUtils.NULL_CHANNEL_BEAN_NAME)) {
402+
this.discardChannel = new NullChannel();
403+
}
404+
else {
405+
throw ex;
406+
}
407+
}
397408
this.discardChannelName = null;
398409
}
399410
return this.discardChannel;

spring-integration-core/src/main/java/org/springframework/integration/channel/NullChannel.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.integration.support.management.ConfigurableMetricsAware;
2828
import org.springframework.integration.support.management.DefaultMessageChannelMetrics;
2929
import org.springframework.integration.support.management.IntegrationManagedResource;
30+
import org.springframework.integration.support.management.metrics.CounterFacade;
3031
import org.springframework.integration.support.management.metrics.MetricsCaptor;
3132
import org.springframework.integration.support.management.metrics.TimerFacade;
3233
import org.springframework.lang.Nullable;
@@ -68,6 +69,8 @@ public class NullChannel implements PollableChannel,
6869

6970
private TimerFacade successTimer;
7071

72+
private CounterFacade receiveCounter;
73+
7174
@Override
7275
public void setBeanName(String beanName) {
7376
this.beanName = beanName;
@@ -268,6 +271,7 @@ public Message<?> receive() {
268271
if (this.loggingEnabled) {
269272
this.logger.debug("receive called on null channel");
270273
}
274+
incrementReceiveCounter();
271275
return null;
272276
}
273277

@@ -276,6 +280,27 @@ public Message<?> receive(long timeout) {
276280
return receive();
277281
}
278282

283+
private void incrementReceiveCounter() {
284+
if (this.metricsCaptor != null) {
285+
if (this.receiveCounter == null) {
286+
this.receiveCounter = buildReceiveCounter();
287+
}
288+
this.receiveCounter.increment();
289+
}
290+
}
291+
292+
private CounterFacade buildReceiveCounter() {
293+
CounterFacade counterFacade = this.metricsCaptor
294+
.counterBuilder(RECEIVE_COUNTER_NAME)
295+
.tag("name", getComponentName() == null ? "unknown" : getComponentName())
296+
.tag("type", "channel")
297+
.tag("result", "success")
298+
.tag("exception", "none")
299+
.description("Messages received")
300+
.build();
301+
return counterFacade;
302+
}
303+
279304
@Override
280305
public String toString() {
281306
return (this.beanName != null) ? this.beanName : super.toString();
@@ -286,6 +311,9 @@ public void destroy() {
286311
if (this.successTimer != null) {
287312
this.successTimer.remove();
288313
}
314+
if (this.receiveCounter != null) {
315+
this.receiveCounter.remove();
316+
}
289317
}
290318

291319
}

spring-integration-core/src/main/java/org/springframework/integration/transaction/ExpressionEvaluatingTransactionSynchronizationProcessor.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
import org.springframework.expression.EvaluationContext;
2222
import org.springframework.expression.Expression;
2323
import org.springframework.expression.spel.support.StandardEvaluationContext;
24-
import org.springframework.integration.channel.NullChannel;
2524
import org.springframework.integration.context.IntegrationObjectSupport;
2625
import org.springframework.integration.expression.ExpressionUtils;
26+
import org.springframework.lang.Nullable;
2727
import org.springframework.messaging.Message;
2828
import org.springframework.messaging.MessageChannel;
2929
import org.springframework.util.Assert;
@@ -66,11 +66,11 @@ public class ExpressionEvaluatingTransactionSynchronizationProcessor extends Int
6666

6767
private volatile Expression afterRollbackExpression;
6868

69-
private volatile MessageChannel beforeCommitChannel = new NullChannel();
69+
private volatile MessageChannel beforeCommitChannel;
7070

71-
private volatile MessageChannel afterCommitChannel = new NullChannel();
71+
private volatile MessageChannel afterCommitChannel;
7272

73-
private volatile MessageChannel afterRollbackChannel = new NullChannel();
73+
private volatile MessageChannel afterRollbackChannel;
7474

7575
public void setIntegrationEvaluationContext(EvaluationContext evaluationContext) {
7676
this.evaluationContext = evaluationContext;
@@ -129,8 +129,8 @@ public void processAfterRollback(IntegrationResourceHolder holder) {
129129
doProcess(holder, this.afterRollbackExpression, this.afterRollbackChannel, "afterRollback");
130130
}
131131

132-
private void doProcess(IntegrationResourceHolder holder, Expression expression, MessageChannel messageChannel,
133-
String expressionType) {
132+
private void doProcess(IntegrationResourceHolder holder, Expression expression,
133+
@Nullable MessageChannel messageChannel, String expressionType) {
134134

135135
Message<?> message = holder.getMessage();
136136
if (message != null) {
@@ -141,7 +141,7 @@ private void doProcess(IntegrationResourceHolder holder, Expression expression,
141141
}
142142
EvaluationContext evaluationContextToUse = prepareEvaluationContextToUse(holder);
143143
Object value = expression.getValue(evaluationContextToUse, message);
144-
if (value != null) {
144+
if (value != null && messageChannel != null) {
145145
if (logger.isDebugEnabled()) {
146146
logger.debug("Sending expression result message to " + messageChannel + " " +
147147
"as part of '" + expressionType + "' transaction synchronization");
@@ -171,7 +171,7 @@ private void doProcess(IntegrationResourceHolder holder, Expression expression,
171171
}
172172
}
173173
}
174-
else {
174+
else if (messageChannel != null) {
175175
if (logger.isDebugEnabled()) {
176176
logger.debug("Sending received message to " + messageChannel + " as part of '" +
177177
expressionType + "' transaction synchronization");

spring-integration-core/src/test/java/org/springframework/integration/config/ResequencerParserTests.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import org.springframework.integration.aggregator.MethodInvokingReleaseStrategy;
3131
import org.springframework.integration.aggregator.ReleaseStrategy;
3232
import org.springframework.integration.aggregator.ResequencingMessageHandler;
33-
import org.springframework.integration.channel.NullChannel;
3433
import org.springframework.integration.endpoint.EventDrivenConsumer;
3534
import org.springframework.integration.store.MessageGroup;
3635
import org.springframework.integration.store.SimpleMessageGroup;
@@ -60,7 +59,6 @@ void testDefaultResequencerProperties() {
6059
ResequencingMessageHandler resequencer = TestUtils.getPropertyValue(endpoint, "handler",
6160
ResequencingMessageHandler.class);
6261
assertThat(getPropertyValue(resequencer, "outputChannel")).isNull();
63-
assertThat(getPropertyValue(resequencer, "discardChannel") instanceof NullChannel).isTrue();
6462
assertThat(getPropertyValue(
6563
resequencer, "messagingTemplate.sendTimeout"))
6664
.as("The ResequencerEndpoint is not set with the appropriate timeout value").isEqualTo(-1L);

spring-integration-core/src/test/java/org/springframework/integration/config/annotation/AggregatorAnnotationTests.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import org.springframework.integration.aggregator.MethodInvokingCorrelationStrategy;
3131
import org.springframework.integration.aggregator.MethodInvokingReleaseStrategy;
3232
import org.springframework.integration.aggregator.SimpleSequenceSizeReleaseStrategy;
33-
import org.springframework.integration.channel.NullChannel;
3433
import org.springframework.integration.endpoint.EventDrivenConsumer;
3534
import org.springframework.integration.test.util.TestUtils;
3635
import org.springframework.messaging.MessageHandler;
@@ -39,6 +38,7 @@
3938
* @author Marius Bogoevici
4039
* @author Mark Fisher
4140
* @author Artem Bilan
41+
* @author Gary Russell
4242
*/
4343
public class AggregatorAnnotationTests {
4444

@@ -51,7 +51,6 @@ public void testAnnotationWithDefaultSettings() {
5151
assertThat(getPropertyValue(aggregator, "releaseStrategy") instanceof SimpleSequenceSizeReleaseStrategy)
5252
.isTrue();
5353
assertThat(getPropertyValue(aggregator, "outputChannel")).isNull();
54-
assertThat(getPropertyValue(aggregator, "discardChannel") instanceof NullChannel).isTrue();
5554
assertThat(getPropertyValue(aggregator, "messagingTemplate.sendTimeout")).isEqualTo(-1L);
5655
assertThat(getPropertyValue(aggregator, "sendPartialResultOnExpiry")).isEqualTo(false);
5756
context.close();

spring-integration-core/src/test/java/org/springframework/integration/endpoint/PseudoTransactionalMessageSourceTests.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,8 @@ public Message<String> receive() {
9696
}
9797
});
9898

99-
MessageChannel afterCommitChannel = TestUtils.getPropertyValue(syncProcessor, "afterCommitChannel",
100-
MessageChannel.class);
101-
assertThat(afterCommitChannel).isInstanceOf(NullChannel.class);
102-
99+
MessageChannel afterCommitChannel = new NullChannel();
100+
syncProcessor.setAfterCommitChannel(afterCommitChannel);
103101
Log logger = TestUtils.getPropertyValue(afterCommitChannel, "logger", Log.class);
104102

105103
logger = Mockito.spy(logger);

spring-integration-file/src/main/java/org/springframework/integration/file/config/FileTailInboundChannelAdapterFactoryBean.java

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,39 +45,43 @@
4545
public class FileTailInboundChannelAdapterFactoryBean extends AbstractFactoryBean<FileTailingMessageProducerSupport>
4646
implements BeanNameAware, SmartLifecycle, ApplicationEventPublisherAware {
4747

48-
private volatile String nativeOptions;
48+
private String nativeOptions;
4949

50-
private volatile boolean enableStatusReader = true;
50+
private boolean enableStatusReader = true;
5151

52-
private volatile Long idleEventInterval;
52+
private Long idleEventInterval;
5353

54-
private volatile File file;
54+
private File file;
5555

56-
private volatile TaskExecutor taskExecutor;
56+
private TaskExecutor taskExecutor;
5757

58-
private volatile TaskScheduler taskScheduler;
58+
private TaskScheduler taskScheduler;
5959

60-
private volatile Long delay;
60+
private Long delay;
6161

62-
private volatile Long fileDelay;
62+
private Long fileDelay;
6363

64-
private volatile Boolean end;
64+
private Boolean end;
6565

66-
private volatile Boolean reopen;
66+
private Boolean reopen;
6767

68-
private volatile FileTailingMessageProducerSupport tailAdapter;
68+
private FileTailingMessageProducerSupport tailAdapter;
6969

70-
private volatile String beanName;
70+
private String beanName;
7171

72-
private volatile MessageChannel outputChannel;
72+
private MessageChannel outputChannel;
7373

74-
private volatile MessageChannel errorChannel;
74+
private MessageChannel errorChannel;
7575

76-
private volatile Boolean autoStartup;
76+
private String outputChannelName;
7777

78-
private volatile Integer phase;
78+
private String errorChannelName;
7979

80-
private volatile ApplicationEventPublisher applicationEventPublisher;
80+
private Boolean autoStartup;
81+
82+
private Integer phase;
83+
84+
private ApplicationEventPublisher applicationEventPublisher;
8185

8286
public void setNativeOptions(String nativeOptions) {
8387
if (StringUtils.hasText(nativeOptions)) {
@@ -141,10 +145,18 @@ public void setOutputChannel(MessageChannel outputChannel) {
141145
this.outputChannel = outputChannel;
142146
}
143147

148+
public void setOutputChannelName(String outputChannelName) {
149+
this.outputChannelName = outputChannelName;
150+
}
151+
144152
public void setErrorChannel(MessageChannel errorChannel) {
145153
this.errorChannel = errorChannel;
146154
}
147155

156+
public void setErrorChannelName(String errorChannelName) {
157+
this.errorChannelName = errorChannelName;
158+
}
159+
148160
public void setAutoStartup(boolean autoStartup) {
149161
this.autoStartup = autoStartup;
150162
}
@@ -238,6 +250,8 @@ protected FileTailingMessageProducerSupport createInstance() {
238250
.acceptIfNotNull(this.autoStartup, adapter::setAutoStartup)
239251
.acceptIfNotNull(this.phase, adapter::setPhase)
240252
.acceptIfNotNull(this.applicationEventPublisher, adapter::setApplicationEventPublisher)
253+
.acceptIfNotNull(this.outputChannelName, adapter::setOutputChannelName)
254+
.acceptIfNotNull(this.errorChannelName, adapter::setErrorChannelName)
241255
.acceptIfNotNull(beanFactory, adapter::setBeanFactory);
242256
adapter.afterPropertiesSet();
243257
this.tailAdapter = adapter;

spring-integration-file/src/main/java/org/springframework/integration/file/dsl/TailAdapterSpec.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020

2121
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
2222
import org.springframework.core.task.TaskExecutor;
23-
import org.springframework.integration.channel.NullChannel;
2423
import org.springframework.integration.dsl.MessageProducerSpec;
2524
import org.springframework.integration.file.config.FileTailInboundChannelAdapterFactoryBean;
2625
import org.springframework.integration.file.tail.FileTailingMessageProducerSupport;
@@ -32,6 +31,7 @@
3231
* A {@link MessageProducerSpec} for file tailing adapters.
3332
*
3433
* @author Artem Bilan
34+
* @author Gary Russell
3535
*
3636
* @since 5.0
3737
*/
@@ -186,9 +186,6 @@ public TailAdapterSpec errorChannel(MessageChannel errorChannel) {
186186

187187
@Override
188188
protected FileTailingMessageProducerSupport doGet() {
189-
if (this.outputChannel == null) {
190-
this.factoryBean.setOutputChannel(new NullChannel());
191-
}
192189
FileTailingMessageProducerSupport tailingMessageProducerSupport = null;
193190
try {
194191
this.factoryBean.afterPropertiesSet();

0 commit comments

Comments
 (0)