diff --git a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java index a4205df6e6e..03dbc0bc56d 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java @@ -211,8 +211,7 @@ public void setChannelResolver(DestinationResolver channelResolv } @Override - @Nullable - public Expression getExpression() { + public @Nullable Expression getExpression() { return this.expression; } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/AbstractInternetProtocolReceivingChannelAdapter.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/AbstractInternetProtocolReceivingChannelAdapter.java index 9649777e99a..e337adc0f42 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/AbstractInternetProtocolReceivingChannelAdapter.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/AbstractInternetProtocolReceivingChannelAdapter.java @@ -20,6 +20,8 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import org.jspecify.annotations.Nullable; + import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.integration.endpoint.MessageProducerSupport; @@ -41,6 +43,7 @@ public abstract class AbstractInternetProtocolReceivingChannelAdapter private final int port; + @SuppressWarnings("NullAway.Init") private ApplicationEventPublisher applicationEventPublisher; private int soTimeout = 0; @@ -49,9 +52,9 @@ public abstract class AbstractInternetProtocolReceivingChannelAdapter private int receiveBufferSize = 2048; // NOSONAR magic number - private String localAddress; + private @Nullable String localAddress; - private Executor taskExecutor; + private @Nullable Executor taskExecutor; private boolean taskExecutorSet; @@ -117,7 +120,7 @@ public void setListening(boolean listening) { this.listening = listening; } - public String getLocalAddress() { + public @Nullable String getLocalAddress() { return this.localAddress; } @@ -139,7 +142,7 @@ public void setTaskExecutor(Executor taskExecutor) { /** * @return the taskExecutor */ - public Executor getTaskExecutor() { + public @Nullable Executor getTaskExecutor() { return this.taskExecutor; } @@ -153,6 +156,7 @@ public void setApplicationEventPublisher(ApplicationEventPublisher applicationEv } @Override + @SuppressWarnings("NullAway") // Dataflow analysis limitation protected void doStart() { String beanName = getComponentName(); checkTaskExecutor((beanName == null ? "" : beanName + "-") + getComponentType()); @@ -179,8 +183,9 @@ protected void checkTaskExecutor(final String threadName) { @Override protected void doStop() { - if (!this.taskExecutorSet && this.taskExecutor != null) { - ((ExecutorService) this.taskExecutor).shutdown(); + Executor taskExecutorToShutdown = this.taskExecutor; + if (!this.taskExecutorSet && taskExecutorToShutdown != null) { + ((ExecutorService) taskExecutorToShutdown).shutdown(); this.taskExecutor = null; } } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/config/TcpConnectionFactoryFactoryBean.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/config/TcpConnectionFactoryFactoryBean.java index 4c2e07c78e8..11aace8bda9 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/config/TcpConnectionFactoryFactoryBean.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/config/TcpConnectionFactoryFactoryBean.java @@ -18,6 +18,8 @@ import java.util.concurrent.Executor; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanNameAware; @@ -62,11 +64,12 @@ public class TcpConnectionFactoryFactoryBean extends AbstractFactoryBean implements Lifecycle, BeanNameAware, ApplicationEventPublisherAware, ApplicationContextAware { + @SuppressWarnings("NullAway.Init") private AbstractConnectionFactory connectionFactory; - private String type; + private @Nullable String type; - private String host; + private @Nullable String host; private int port; @@ -84,7 +87,7 @@ public class TcpConnectionFactoryFactoryBean extends AbstractFactoryBean deserializer = new ByteArrayCrLfSerializer(); @@ -98,38 +101,41 @@ public class TcpConnectionFactoryFactoryBean extends AbstractFactoryBean implements ComponentsRegistration { - protected final AbstractConnectionFactory connectionFactory; // NOSONAR - final + protected final @Nullable AbstractConnectionFactory connectionFactory; // NOSONAR - final /** * Construct an instance using an existing spring-managed connection factory. @@ -91,10 +93,10 @@ public TcpInboundChannelAdapterSpec taskScheduler(TaskScheduler taskScheduler) { } @Override - public Map getComponentsToRegister() { + public Map getComponentsToRegister() { return this.connectionFactory != null - ? Collections.singletonMap(this.connectionFactory, this.connectionFactory.getComponentName()) - : Collections.emptyMap(); + ? Collections.singletonMap(this.connectionFactory, this.connectionFactory.getComponentName()) + : Collections.emptyMap(); } } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/dsl/TcpInboundGatewaySpec.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/dsl/TcpInboundGatewaySpec.java index c017ccb88a8..d883291998a 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/dsl/TcpInboundGatewaySpec.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/dsl/TcpInboundGatewaySpec.java @@ -19,6 +19,8 @@ import java.util.Collections; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.integration.dsl.ComponentsRegistration; import org.springframework.integration.dsl.MessagingGatewaySpec; import org.springframework.integration.ip.tcp.TcpInboundGateway; @@ -37,7 +39,7 @@ public class TcpInboundGatewaySpec extends MessagingGatewaySpec implements ComponentsRegistration { - protected final AbstractConnectionFactory connectionFactory; // NOSONAR - final + protected final @Nullable AbstractConnectionFactory connectionFactory; // NOSONAR - final /** * Construct an instance using an existing spring-managed connection factory. @@ -90,10 +92,10 @@ public TcpInboundGatewaySpec taskScheduler(TaskScheduler taskScheduler) { } @Override - public Map getComponentsToRegister() { + public Map getComponentsToRegister() { return this.connectionFactory != null - ? Collections.singletonMap(this.connectionFactory, this.connectionFactory.getComponentName()) - : Collections.emptyMap(); + ? Collections.singletonMap(this.connectionFactory, this.connectionFactory.getComponentName()) + : Collections.emptyMap(); } } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/dsl/TcpOutboundChannelAdapterSpec.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/dsl/TcpOutboundChannelAdapterSpec.java index a3702c3f42b..a64fec9a275 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/dsl/TcpOutboundChannelAdapterSpec.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/dsl/TcpOutboundChannelAdapterSpec.java @@ -19,6 +19,8 @@ import java.util.Collections; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.integration.dsl.ComponentsRegistration; import org.springframework.integration.dsl.MessageHandlerSpec; import org.springframework.integration.ip.tcp.TcpSendingMessageHandler; @@ -38,7 +40,7 @@ public class TcpOutboundChannelAdapterSpec extends MessageHandlerSpec implements ComponentsRegistration { - protected final AbstractConnectionFactory connectionFactory; // NOSONAR - final + protected final @Nullable AbstractConnectionFactory connectionFactory; // NOSONAR - final /** * Construct an instance using an existing spring-managed connection factory. @@ -91,10 +93,10 @@ public TcpOutboundChannelAdapterSpec taskScheduler(TaskScheduler taskScheduler) } @Override - public Map getComponentsToRegister() { + public Map getComponentsToRegister() { return this.connectionFactory != null - ? Collections.singletonMap(this.connectionFactory, this.connectionFactory.getComponentName()) - : Collections.emptyMap(); + ? Collections.singletonMap(this.connectionFactory, this.connectionFactory.getComponentName()) + : Collections.emptyMap(); } } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/dsl/TcpOutboundGatewaySpec.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/dsl/TcpOutboundGatewaySpec.java index 59248f7ec2b..885157d1877 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/dsl/TcpOutboundGatewaySpec.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/dsl/TcpOutboundGatewaySpec.java @@ -20,6 +20,8 @@ import java.util.Map; import java.util.function.Function; +import org.jspecify.annotations.Nullable; + import org.springframework.integration.dsl.ComponentsRegistration; import org.springframework.integration.dsl.MessageHandlerSpec; import org.springframework.integration.expression.FunctionExpression; @@ -40,7 +42,7 @@ public class TcpOutboundGatewaySpec extends MessageHandlerSpec implements ComponentsRegistration { - protected final AbstractClientConnectionFactory connectionFactory; // NOSONAR - final + protected final @Nullable AbstractClientConnectionFactory connectionFactory; // NOSONAR - final /** * Construct an instance using an existing spring-managed connection factory. @@ -138,10 +140,10 @@ public TcpOutboundGatewaySpec unsolicitedMessageChannel(MessageChannel channel) } @Override - public Map getComponentsToRegister() { + public Map getComponentsToRegister() { return this.connectionFactory != null - ? Collections.singletonMap(this.connectionFactory, this.connectionFactory.getComponentName()) - : Collections.emptyMap(); + ? Collections.singletonMap(this.connectionFactory, this.connectionFactory.getComponentName()) + : Collections.emptyMap(); } } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/dsl/package-info.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/dsl/package-info.java index ec6063a0eaa..50420e409e5 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/dsl/package-info.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/dsl/package-info.java @@ -1,5 +1,5 @@ /** * Provides TCP/UDP Component support for the Java DSL. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.integration.ip.dsl; diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/event/package-info.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/event/package-info.java index 0edff17fc27..36e484cf46d 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/event/package-info.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/event/package-info.java @@ -1,4 +1,5 @@ /** * ApplicationEvents generated by the ip module. */ +@org.jspecify.annotations.NullMarked package org.springframework.integration.ip.event; diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/package-info.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/package-info.java index ffdae6527f7..9c0cf19768c 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/package-info.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/package-info.java @@ -1,4 +1,5 @@ /** * Base package for IP (TCP/UDP) Support. */ +@org.jspecify.annotations.NullMarked package org.springframework.integration.ip; diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/TcpInboundGateway.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/TcpInboundGateway.java index e2df1d327d3..12564057096 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/TcpInboundGateway.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/TcpInboundGateway.java @@ -22,7 +22,8 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.atomic.AtomicInteger; -import org.springframework.context.ApplicationEventPublisher; +import org.jspecify.annotations.Nullable; + import org.springframework.integration.context.OrderlyShutdownCapable; import org.springframework.integration.gateway.MessagingGatewaySupport; import org.springframework.integration.ip.IpHeaders; @@ -38,7 +39,6 @@ import org.springframework.messaging.Message; import org.springframework.messaging.MessagingException; import org.springframework.messaging.support.ErrorMessage; -import org.springframework.scheduling.TaskScheduler; import org.springframework.util.Assert; /** @@ -47,7 +47,7 @@ * For java.nio connections, messages may be multiplexed but the client will need to * provide correlation logic. If the client is a {@link TcpOutboundGateway} multiplexing * is not used, but multiple concurrent connections can be used if the connection factory uses - * single-use connections. For true asynchronous bi-directional communication, a pair of + * single-use connections. For true asynchronous bidirectional communication, a pair of * inbound / outbound channel adapters should be used. * * @author Gary Russell @@ -67,9 +67,9 @@ public class TcpInboundGateway extends MessagingGatewaySupport implements private final AtomicInteger activeCount = new AtomicInteger(); - private AbstractServerConnectionFactory serverConnectionFactory; + private @Nullable AbstractServerConnectionFactory serverConnectionFactory; - private AbstractClientConnectionFactory clientConnectionFactory; + private @Nullable AbstractClientConnectionFactory clientConnectionFactory; private boolean isClientMode; @@ -77,9 +77,9 @@ public class TcpInboundGateway extends MessagingGatewaySupport implements private long retryInterval = DEFAULT_RETRY_INTERVAL; - private volatile ClientModeConnectionManager clientModeConnectionManager; + private volatile @Nullable ClientModeConnectionManager clientModeConnectionManager; - private volatile ScheduledFuture scheduledFuture; + private volatile @Nullable ScheduledFuture scheduledFuture; private volatile boolean shuttingDown; @@ -114,7 +114,7 @@ public boolean onMessage(Message message) { if (this.serverConnectionFactory != null) { this.serverConnectionFactory.closeConnection(connectionId); } - else { + else if (this.clientConnectionFactory != null) { this.clientConnectionFactory.closeConnection(connectionId); } } @@ -128,35 +128,33 @@ private boolean doOnMessage(Message message) { return false; } String connectionId = (String) message.getHeaders().get(IpHeaders.CONNECTION_ID); - TcpConnection connection = null; if (connectionId != null) { - connection = this.connections.get(connectionId); - } - if (connection == null) { - publishNoConnectionEvent(message, connectionId); - logger.error(() -> "Connection not found when processing reply " + reply + " for " + message); - return false; - } - try { - connection.send(reply); - } - catch (Exception ex) { - logger.error(ex, "Failed to send reply"); + TcpConnection connection = this.connections.get(connectionId); + if (connection == null) { + publishNoConnectionEvent(message, connectionId); + logger.error(() -> "Connection not found when processing reply " + reply + " for " + message); + return false; + } + try { + connection.send(reply); + } + catch (Exception ex) { + logger.error(ex, "Failed to send reply"); + } } return false; } + @SuppressWarnings("NullAway") // Dataflow analysis limitation private void publishNoConnectionEvent(Message message, String connectionId) { AbstractConnectionFactory cf = this.serverConnectionFactory != null ? this.serverConnectionFactory : this.clientConnectionFactory; - ApplicationEventPublisher applicationEventPublisher = cf.getApplicationEventPublisher(); - if (applicationEventPublisher != null) { - applicationEventPublisher.publishEvent( - new TcpConnectionFailedCorrelationEvent(this, connectionId, - new MessagingException(message, "Connection not found to process reply."))); - } + + cf.getApplicationEventPublisher().publishEvent( + new TcpConnectionFailedCorrelationEvent(this, connectionId, + new MessagingException(message, "Connection not found to process reply."))); } /** @@ -205,6 +203,8 @@ public String getComponentType() { @Override protected void onInit() { super.onInit(); + Assert.state(this.serverConnectionFactory != null || this.clientConnectionFactory != null, + "An 'AbstractConnectionFactory' must not be provided."); if (this.isClientMode) { Assert.notNull(this.clientConnectionFactory, "For client-mode, connection factory must be type='client'"); Assert.isTrue(!this.clientConnectionFactory.isSingleUse(), @@ -222,21 +222,20 @@ protected void doStart() { if (this.clientConnectionFactory != null) { this.clientConnectionFactory.start(); } - if (this.isClientMode) { + if (this.isClientMode && this.clientConnectionFactory != null) { ClientModeConnectionManager manager = new ClientModeConnectionManager(this.clientConnectionFactory); this.clientModeConnectionManager = manager; - TaskScheduler taskScheduler = getTaskScheduler(); - Assert.state(taskScheduler != null, "Client mode requires a task scheduler"); - this.scheduledFuture = taskScheduler.scheduleAtFixedRate(manager, Duration.ofMillis(this.retryInterval)); + this.scheduledFuture = getTaskScheduler().scheduleAtFixedRate(manager, Duration.ofMillis(this.retryInterval)); } } @Override // protected by super#lifecycleLock protected void doStop() { super.doStop(); - if (this.scheduledFuture != null) { - this.scheduledFuture.cancel(true); + ScheduledFuture scheduledFutureToCancel = this.scheduledFuture; + if (scheduledFutureToCancel != null) { + scheduledFutureToCancel.cancel(true); } this.clientModeConnectionManager = null; if (this.clientConnectionFactory != null) { @@ -281,8 +280,9 @@ public void setRetryInterval(long retryInterval) { @Override public boolean isClientModeConnected() { - if (this.isClientMode && this.clientModeConnectionManager != null) { - return this.clientModeConnectionManager.isConnected(); + ClientModeConnectionManager clientModeConnectionManagerToCheck = this.clientModeConnectionManager; + if (this.isClientMode && clientModeConnectionManagerToCheck != null) { + return clientModeConnectionManagerToCheck.isConnected(); } else { return false; @@ -291,8 +291,9 @@ public boolean isClientModeConnected() { @Override public void retryConnection() { - if (isActive() && this.isClientMode && this.clientModeConnectionManager != null) { - this.clientModeConnectionManager.run(); + ClientModeConnectionManager clientModeConnectionManagerToRun = this.clientModeConnectionManager; + if (isActive() && this.isClientMode && clientModeConnectionManagerToRun != null) { + clientModeConnectionManagerToRun.run(); } } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/TcpOutboundGateway.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/TcpOutboundGateway.java index b4c938fad1e..9548946f5e7 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/TcpOutboundGateway.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/TcpOutboundGateway.java @@ -26,7 +26,8 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; -import org.springframework.context.ApplicationEventPublisher; +import org.jspecify.annotations.Nullable; + import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; import org.springframework.expression.spel.support.StandardEvaluationContext; @@ -76,6 +77,7 @@ public class TcpOutboundGateway extends AbstractReplyProducingMessageHandler private final Semaphore semaphore = new Semaphore(1, true); + @SuppressWarnings("NullAway.Init") private AbstractClientConnectionFactory connectionFactory; private boolean isSingleUse; @@ -92,9 +94,9 @@ public class TcpOutboundGateway extends AbstractReplyProducingMessageHandler private boolean closeStreamAfterSend; - private String unsolicitedMessageChannelName; + private @Nullable String unsolicitedMessageChannelName; - private MessageChannel unsolicitedMessageChannel; + private @Nullable MessageChannel unsolicitedMessageChannel; public void setConnectionFactory(AbstractClientConnectionFactory connectionFactory) { this.connectionFactory = connectionFactory; @@ -199,6 +201,7 @@ public String getComponentType() { @Override protected void doInit() { super.doInit(); + Assert.notNull(this.connectionFactory, () -> getClass().getName() + " requires a client connection factory"); if (!this.evaluationContextSet) { this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(getBeanFactory()); } @@ -208,7 +211,6 @@ protected void doInit() { @Override protected Object handleRequestMessage(Message requestMessage) { - Assert.notNull(this.connectionFactory, () -> getClass().getName() + " requires a client connection factory"); boolean haveSemaphore = false; TcpConnection connection = null; String connectionId = null; @@ -306,11 +308,11 @@ private Message getReply(Message requestMessage, TcpConnection connection, return replyMessage; } - private void cleanUp(boolean haveSemaphore, TcpConnection connection, String connectionId) { + private void cleanUp(boolean haveSemaphore, @Nullable TcpConnection connection, @Nullable String connectionId) { if (connectionId != null) { this.pendingReplies.remove(connectionId); logger.debug(() -> "Removed pending reply " + connectionId); - if (this.isSingleUse) { + if (this.isSingleUse && connection != null) { connection.close(); } } @@ -379,12 +381,10 @@ private boolean unsolicitedSupported(Message message) { return false; } - private void publishNoConnectionEvent(Message message, String connectionId, String errorMessage) { - ApplicationEventPublisher applicationEventPublisher = this.connectionFactory.getApplicationEventPublisher(); - if (applicationEventPublisher != null) { - applicationEventPublisher.publishEvent(new TcpConnectionFailedCorrelationEvent(this, connectionId, - new MessagingException(message, errorMessage))); - } + private void publishNoConnectionEvent(Message message, @Nullable String connectionId, String errorMessage) { + this.connectionFactory.getApplicationEventPublisher() + .publishEvent(new TcpConnectionFailedCorrelationEvent( + this, connectionId, new MessagingException(message, errorMessage))); } @Override @@ -437,13 +437,13 @@ private final class AsyncReply { private final boolean haveSemaphore; - private final ScheduledFuture noResponseFuture; + private final @Nullable ScheduledFuture noResponseFuture; private final CompletableFuture> future = new CompletableFuture>() .thenApply(this::cancelNoResponseFutureIfAny); - private volatile Message reply; + private volatile @Nullable Message reply; AsyncReply(long remoteTimeout, TcpConnection connection, boolean haveSemaphore, Message requestMessage, boolean async) { @@ -489,7 +489,7 @@ boolean isHaveSemaphore() { * Sender blocks here until the reply is received, or we time out. * @return The return message or null if we time out */ - Message getReply() { + @Nullable Message getReply() { try { if (!this.latch.await(this.remoteTimeout, TimeUnit.MILLISECONDS)) { return null; @@ -528,17 +528,21 @@ CompletableFuture> getFuture() { } private void doThrowErrorMessagePayload() { - if (this.reply.getPayload() instanceof MessagingException) { - throw (MessagingException) this.reply.getPayload(); - } - else { - throw new MessagingException("Exception while awaiting reply", (Throwable) this.reply.getPayload()); + Message replyToCheck = this.reply; + if (replyToCheck != null) { + Object payload = replyToCheck.getPayload(); + if (payload instanceof MessagingException) { + throw (MessagingException) payload; + } + else { + throw new MessagingException("Exception while awaiting reply", (Throwable) payload); + } } } /** * We have a race condition when a socket is closed right after the reply is received. The close "error" - * might arrive before the actual reply. Overwrite an error with a good reply, but not vice-versa. + * might arrive before the actual reply. Overwrite an error with a good reply, but not vice versa. * @param reply the reply message. */ public void setReply(Message reply) { diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/TcpReceivingChannelAdapter.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/TcpReceivingChannelAdapter.java index 964ab66dfb7..e346e486fa0 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/TcpReceivingChannelAdapter.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/TcpReceivingChannelAdapter.java @@ -20,6 +20,8 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.atomic.AtomicInteger; +import org.jspecify.annotations.Nullable; + import org.springframework.integration.context.OrderlyShutdownCapable; import org.springframework.integration.endpoint.MessageProducerSupport; import org.springframework.integration.ip.IpHeaders; @@ -32,7 +34,6 @@ import org.springframework.integration.ip.tcp.connection.TcpListener; import org.springframework.messaging.Message; import org.springframework.messaging.support.ErrorMessage; -import org.springframework.scheduling.TaskScheduler; import org.springframework.util.Assert; /** @@ -50,9 +51,9 @@ public class TcpReceivingChannelAdapter extends MessageProducerSupport implements TcpListener, ClientModeCapable, OrderlyShutdownCapable { - private AbstractConnectionFactory clientConnectionFactory; + private @Nullable AbstractConnectionFactory clientConnectionFactory; - private AbstractConnectionFactory serverConnectionFactory; + private @Nullable AbstractConnectionFactory serverConnectionFactory; private volatile boolean isSingleUse; @@ -60,9 +61,9 @@ public class TcpReceivingChannelAdapter private volatile long retryInterval = 60000; // NOSONAR magic number - private volatile ScheduledFuture scheduledFuture; + private volatile @Nullable ScheduledFuture scheduledFuture; - private volatile ClientModeConnectionManager clientModeConnectionManager; + private volatile @Nullable ClientModeConnectionManager clientModeConnectionManager; private volatile boolean shuttingDown; @@ -103,7 +104,7 @@ public boolean onMessage(Message message) { this.serverConnectionFactory.closeConnection(connectionId); } } - else { + else if (this.clientConnectionFactory != null) { this.clientConnectionFactory.closeConnection(connectionId); } } @@ -130,19 +131,18 @@ protected void doStart() { if (this.clientConnectionFactory != null) { this.clientConnectionFactory.start(); } - if (this.isClientMode) { + if (this.isClientMode && this.clientConnectionFactory != null) { ClientModeConnectionManager manager = new ClientModeConnectionManager(this.clientConnectionFactory); this.clientModeConnectionManager = manager; - TaskScheduler taskScheduler = getTaskScheduler(); - Assert.state(taskScheduler != null, "Client mode requires a task scheduler"); - this.scheduledFuture = taskScheduler.scheduleAtFixedRate(manager, Duration.ofMillis(this.retryInterval)); + this.scheduledFuture = getTaskScheduler().scheduleAtFixedRate(manager, Duration.ofMillis(this.retryInterval)); } } @Override // protected by super#lifecycleLock protected void doStop() { - if (this.scheduledFuture != null) { - this.scheduledFuture.cancel(true); + ScheduledFuture scheduledFutureToCancel = this.scheduledFuture; + if (scheduledFutureToCancel != null) { + scheduledFutureToCancel.cancel(true); } this.clientModeConnectionManager = null; if (this.clientConnectionFactory != null) { @@ -188,14 +188,14 @@ public String getComponentType() { /** * @return the clientConnectionFactory */ - protected ConnectionFactory getClientConnectionFactory() { + protected @Nullable ConnectionFactory getClientConnectionFactory() { return this.clientConnectionFactory; } /** * @return the serverConnectionFactory */ - protected ConnectionFactory getServerConnectionFactory() { + protected @Nullable ConnectionFactory getServerConnectionFactory() { return this.serverConnectionFactory; } @@ -230,8 +230,9 @@ public void setRetryInterval(long retryInterval) { @Override public boolean isClientModeConnected() { - if (this.isClientMode && this.clientModeConnectionManager != null) { - return this.clientModeConnectionManager.isConnected(); + ClientModeConnectionManager clientModeConnectionManagerToCheck = this.clientModeConnectionManager; + if (this.isClientMode && clientModeConnectionManagerToCheck != null) { + return clientModeConnectionManagerToCheck.isConnected(); } else { return false; @@ -240,8 +241,9 @@ public boolean isClientModeConnected() { @Override public void retryConnection() { - if (isActive() && this.isClientMode && this.clientModeConnectionManager != null) { - this.clientModeConnectionManager.run(); + ClientModeConnectionManager clientModeConnectionManagerToRun = this.clientModeConnectionManager; + if (isActive() && this.isClientMode && clientModeConnectionManagerToRun != null) { + clientModeConnectionManagerToRun.run(); } } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/TcpSendingMessageHandler.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/TcpSendingMessageHandler.java index f78873037fb..c389af50467 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/TcpSendingMessageHandler.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/TcpSendingMessageHandler.java @@ -24,7 +24,8 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import org.springframework.context.ApplicationEventPublisher; +import org.jspecify.annotations.Nullable; + import org.springframework.integration.handler.AbstractMessageHandler; import org.springframework.integration.ip.IpHeaders; import org.springframework.integration.ip.tcp.connection.AbstractClientConnectionFactory; @@ -39,7 +40,6 @@ import org.springframework.integration.support.utils.IntegrationUtils; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHandlingException; -import org.springframework.scheduling.TaskScheduler; import org.springframework.util.Assert; /** @@ -67,9 +67,9 @@ public class TcpSendingMessageHandler extends AbstractMessageHandler implements private final Map connections = new ConcurrentHashMap<>(); - private AbstractConnectionFactory clientConnectionFactory; + private @Nullable AbstractConnectionFactory clientConnectionFactory; - private AbstractConnectionFactory serverConnectionFactory; + private @Nullable AbstractConnectionFactory serverConnectionFactory; private boolean isClientMode; @@ -77,9 +77,9 @@ public class TcpSendingMessageHandler extends AbstractMessageHandler implements private long retryInterval = DEFAULT_RETRY_INTERVAL; - private volatile ScheduledFuture scheduledFuture; + private volatile @Nullable ScheduledFuture scheduledFuture; - private volatile ClientModeConnectionManager clientModeConnectionManager; + private volatile @Nullable ClientModeConnectionManager clientModeConnectionManager; private volatile boolean active; @@ -157,7 +157,9 @@ private void handleMessageAsClient(Message message) { } } finally { - if (connection != null && this.isSingleUse + if (connection != null + && this.isSingleUse + && this.clientConnectionFactory != null && this.clientConnectionFactory.getListener() == null) { // if there's no collaborating inbound adapter, close immediately, otherwise // it will close after receiving the reply. @@ -194,16 +196,17 @@ protected TcpConnection doWrite(Message message) { return connection; } - private void publishNoConnectionEvent(MessageHandlingException messageHandlingException, String connectionId) { + @SuppressWarnings("NullAway") // Dataflow analysis limitation + private void publishNoConnectionEvent(MessageHandlingException messageHandlingException, + @Nullable String connectionId) { + AbstractConnectionFactory cf = this.serverConnectionFactory != null ? this.serverConnectionFactory : this.clientConnectionFactory; - ApplicationEventPublisher applicationEventPublisher = cf.getApplicationEventPublisher(); - if (applicationEventPublisher != null) { - applicationEventPublisher.publishEvent( - new TcpConnectionFailedCorrelationEvent(this, connectionId, messageHandlingException)); - } + + cf.getApplicationEventPublisher().publishEvent( + new TcpConnectionFailedCorrelationEvent(this, connectionId, messageHandlingException)); } /** @@ -267,10 +270,8 @@ public void start() { ClientModeConnectionManager manager = new ClientModeConnectionManager(this.clientConnectionFactory); this.clientModeConnectionManager = manager; - TaskScheduler taskScheduler = getTaskScheduler(); - Assert.state(taskScheduler != null, "Client mode requires a task scheduler"); this.scheduledFuture = - taskScheduler.scheduleAtFixedRate(manager, Duration.ofMillis(this.retryInterval)); + getTaskScheduler().scheduleAtFixedRate(manager, Duration.ofMillis(this.retryInterval)); } } } @@ -285,8 +286,9 @@ public void stop() { try { if (this.active) { this.active = false; - if (this.scheduledFuture != null) { - this.scheduledFuture.cancel(true); + ScheduledFuture scheduledFutureToCancel = this.scheduledFuture; + if (scheduledFutureToCancel != null) { + scheduledFutureToCancel.cancel(true); } this.clientModeConnectionManager = null; if (this.clientConnectionFactory != null) { @@ -310,14 +312,14 @@ public boolean isRunning() { /** * @return the clientConnectionFactory */ - protected ConnectionFactory getClientConnectionFactory() { + protected @Nullable ConnectionFactory getClientConnectionFactory() { return this.clientConnectionFactory; } /** * @return the serverConnectionFactory */ - protected ConnectionFactory getServerConnectionFactory() { + protected @Nullable ConnectionFactory getServerConnectionFactory() { return this.serverConnectionFactory; } @@ -359,8 +361,9 @@ public void setRetryInterval(long retryInterval) { @Override public boolean isClientModeConnected() { - if (this.isClientMode && this.clientModeConnectionManager != null) { - return this.clientModeConnectionManager.isConnected(); + ClientModeConnectionManager clientModeConnectionManagerToCheck = this.clientModeConnectionManager; + if (this.isClientMode && clientModeConnectionManagerToCheck != null) { + return clientModeConnectionManagerToCheck.isConnected(); } else { return false; @@ -369,8 +372,9 @@ public boolean isClientModeConnected() { @Override public void retryConnection() { - if (this.active && this.isClientMode && this.clientModeConnectionManager != null) { - this.clientModeConnectionManager.run(); + ClientModeConnectionManager clientModeConnectionManagerToRun = this.clientModeConnectionManager; + if (this.active && this.isClientMode && clientModeConnectionManagerToRun != null) { + clientModeConnectionManagerToRun.run(); } } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractClientConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractClientConnectionFactory.java index 3471d1c150c..2bb2439d82e 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractClientConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractClientConnectionFactory.java @@ -25,8 +25,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Predicate; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * Abstract class for client connection factories; client connection factories @@ -49,13 +48,12 @@ public abstract class AbstractClientConnectionFactory extends AbstractConnection private Duration connectTimeout = Duration.ofSeconds(DEFAULT_CONNECT_TIMEOUT); - @Nullable - private Predicate connectionTest; + private @Nullable Predicate connectionTest; - private volatile TcpConnectionSupport theConnection; + private volatile @Nullable TcpConnectionSupport theConnection; /** - * Construct a factory that will established connections to the host and port. + * Construct a factory that will establish connections to the host and port. * @param host The host. * @param port The port. */ @@ -93,8 +91,7 @@ public void enableManualListenerRegistration() { * @return the predicate. * @since 5.3 */ - @Nullable - protected Predicate getConnectionTest() { + protected @Nullable Predicate getConnectionTest() { return this.connectionTest; } @@ -130,8 +127,7 @@ protected TcpConnectionSupport obtainConnection() throws InterruptedException { return obtainNewConnection(); } - @Nullable - protected final TcpConnectionSupport obtainSharedConnection() throws InterruptedException { + protected final @Nullable TcpConnectionSupport obtainSharedConnection() throws InterruptedException { this.theConnectionLock.readLock().lockInterruptibly(); try { TcpConnectionSupport connection = getTheConnection(); @@ -162,10 +158,7 @@ protected final TcpConnectionSupport obtainNewConnection() throws InterruptedExc return doObtain(singleUse); } catch (RuntimeException e) { - ApplicationEventPublisher applicationEventPublisher = getApplicationEventPublisher(); - if (applicationEventPublisher != null) { - applicationEventPublisher.publishEvent(new TcpConnectionFailedEvent(this, e)); - } + getApplicationEventPublisher().publishEvent(new TcpConnectionFailedEvent(this, e)); throw e; } finally { @@ -234,8 +227,7 @@ protected void setTheConnection(TcpConnectionSupport theConnection) { /** * @return the theConnection */ - @Nullable - protected TcpConnectionSupport getTheConnection() { + protected @Nullable TcpConnectionSupport getTheConnection() { return this.theConnection; } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractConnectionFactory.java index 25e6593381c..0b54e23dcf8 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractConnectionFactory.java @@ -45,13 +45,14 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import org.jspecify.annotations.Nullable; + import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.core.serializer.Deserializer; import org.springframework.core.serializer.Serializer; import org.springframework.integration.context.IntegrationObjectSupport; import org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer; -import org.springframework.lang.Nullable; import org.springframework.messaging.MessagingException; import org.springframework.util.Assert; @@ -87,11 +88,11 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport private final List senders = Collections.synchronizedList(new ArrayList<>()); - private String host; + private @Nullable String host; private int port; - private TcpListener listener; + private @Nullable TcpListener listener; private int soTimeout = -1; @@ -107,7 +108,7 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport private int soTrafficClass = -1; // don't set by default - private Executor taskExecutor; + private @Nullable Executor taskExecutor; private boolean privateExecutor; @@ -123,7 +124,7 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport private boolean singleUse; - private TcpConnectionInterceptorFactoryChain interceptorFactoryChain; + private @Nullable TcpConnectionInterceptorFactoryChain interceptorFactoryChain; private boolean lookupHost; @@ -133,11 +134,12 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport private int nioHarvestInterval = DEFAULT_NIO_HARVEST_INTERVAL; + @SuppressWarnings("NullAway.Init") private ApplicationEventPublisher applicationEventPublisher; private long readDelay = DEFAULT_READ_DELAY; - private Integer sslHandshakeTimeout; + private @Nullable Integer sslHandshakeTimeout; private volatile boolean active; @@ -159,7 +161,6 @@ public void setApplicationEventPublisher(ApplicationEventPublisher applicationEv } } - @Nullable public ApplicationEventPublisher getApplicationEventPublisher() { return this.applicationEventPublisher; } @@ -301,7 +302,7 @@ public void setHost(String host) { /** * @return the host */ - public String getHost() { + public @Nullable String getHost() { return this.host; } @@ -593,23 +594,25 @@ public void stop() { try { if (this.privateExecutor) { ExecutorService executorService = (ExecutorService) this.taskExecutor; - executorService.shutdown(); - try { - if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) { // NOSONAR magic number - logger.debug("Forcing executor shutdown"); - executorService.shutdownNow(); + if (executorService != null) { + executorService.shutdown(); + try { if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) { // NOSONAR magic number - logger.debug("Executor failed to shutdown"); + logger.debug("Forcing executor shutdown"); + executorService.shutdownNow(); + if (!executorService.awaitTermination(10, TimeUnit.SECONDS)) { // NOSONAR magic number + logger.debug("Executor failed to shutdown"); + } } } - } - catch (@SuppressWarnings(UNUSED) InterruptedException e) { - executorService.shutdownNow(); - Thread.currentThread().interrupt(); - } - finally { - this.taskExecutor = null; - this.privateExecutor = false; + catch (@SuppressWarnings(UNUSED) InterruptedException e) { + executorService.shutdownNow(); + Thread.currentThread().interrupt(); + } + finally { + this.taskExecutor = null; + this.privateExecutor = false; + } } } } @@ -637,7 +640,7 @@ protected TcpConnectionSupport wrapConnection(TcpConnectionSupport connectionArg if (this.listener == null) { connection.registerListener(wrapper); } - if (this.senders.size() == 0) { + if (this.senders.isEmpty()) { connection.registerSender(wrapper); } connection.setWrapped(true); @@ -655,15 +658,14 @@ protected TcpConnectionSupport wrapConnection(TcpConnectionSupport connectionArg * * Times out any expired connections then, if {@code selectionCount > 0}, * processes the selected keys. - * Removes closed connections from the connections field, and from the connections parameter. + * Removes closed connections from the connections field, and from the connections' parameter. * @param selectionCount Number of IO Events, if 0 we were probably woken up by a close. * @param selector The selector. * @param server The server socket channel. * @param connectionMap Map of connections. */ - protected void processNioSelections(int selectionCount, final Selector selector, - @Nullable ServerSocketChannel server, - Map connectionMap) { + protected void processNioSelections(int selectionCount, Selector selector, + @Nullable ServerSocketChannel server, Map connectionMap) { final long now = System.currentTimeMillis(); rescheduleDelayedReads(selector, now); @@ -715,6 +717,7 @@ private void checkChannel(Map connectionMap, fi } else if (this.soTimeout > 0) { TcpNioConnection connection = connectionMap.get(channel); + Assert.state(connection != null, () -> "No 'connection' for channel: " + channel); if (now - connection.getLastRead() >= this.soTimeout) { /* * For client connections, we have to wait for 2 timeouts if the last @@ -722,7 +725,7 @@ else if (this.soTimeout > 0) { */ if (!connection.isServer() && now - connection.getLastSend() < this.soTimeout && - now - connection.getLastRead() < this.soTimeout * 2) { + now - connection.getLastRead() < this.soTimeout * 2L) { logger.debug(() -> "Skipping a connection timeout because we have a recent send " + connection.getConnectionId()); } @@ -737,7 +740,7 @@ else if (this.soTimeout > 0) { } } - private void handleKey(final Selector selector, ServerSocketChannel server, final long now, + private void handleKey(final Selector selector, @Nullable ServerSocketChannel server, final long now, final SelectionKey key) { if (!key.isValid()) { @@ -760,7 +763,7 @@ private void keyReadable(final Selector selector, final long now, final Selectio connection = (TcpNioConnection) key.attachment(); connection.setLastRead(System.currentTimeMillis()); try { - this.taskExecutor.execute(() -> { + getTaskExecutor().execute(() -> { boolean delayed = false; try { connection.readPacket(); @@ -796,12 +799,14 @@ private void keyReadable(final Selector selector, final long now, final Selectio } } - private void keyAcceptable(final Selector selector, ServerSocketChannel server, final long now) { - try { - doAccept(selector, server, now); - } - catch (Exception ex) { - logger.error(ex, "Exception accepting new connection(s)"); + private void keyAcceptable(final Selector selector, @Nullable ServerSocketChannel server, final long now) { + if (server != null) { + try { + doAccept(selector, server, now); + } + catch (Exception ex) { + logger.error(ex, "Exception accepting new connection(s)"); + } } } @@ -1003,16 +1008,7 @@ public String toString() { + ", port=" + getPort(); } - private static final class PendingIO { - - private final long failedAt; - - private final SelectionKey key; - - private PendingIO(long failedAt, SelectionKey key) { - this.failedAt = failedAt; - this.key = key; - } + protected record PendingIO(long failedAt, SelectionKey key) { } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractServerConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractServerConnectionFactory.java index 90bdcf478b6..9b263c5133b 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractServerConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractServerConnectionFactory.java @@ -18,16 +18,15 @@ import java.net.ServerSocket; import java.net.Socket; -import java.net.SocketAddress; import java.net.SocketException; import java.time.Instant; +import org.jspecify.annotations.Nullable; + import org.springframework.context.ApplicationEventPublisher; import org.springframework.core.task.TaskRejectedException; import org.springframework.integration.context.OrderlyShutdownCapable; -import org.springframework.lang.Nullable; import org.springframework.scheduling.SchedulingAwareRunnable; -import org.springframework.scheduling.TaskScheduler; import org.springframework.util.Assert; /** @@ -48,7 +47,7 @@ public abstract class AbstractServerConnectionFactory extends AbstractConnection private int backlog = DEFAULT_BACKLOG; - private String localAddress; + private @Nullable String localAddress; private volatile boolean listening; @@ -67,12 +66,6 @@ public boolean isLongLived() { return true; } - @Override - @Nullable - public SocketAddress getServerSocketAddress() { - return null; - } - @Override public void start() { this.lifecycleMonitor.lock(); @@ -158,8 +151,7 @@ protected void postProcessServerSocket(ServerSocket serverSocket) { * * @return the localAddress */ - @Nullable - public String getLocalAddress() { + public @Nullable String getLocalAddress() { return this.localAddress; } @@ -203,28 +195,17 @@ public int afterShutdown() { } protected void publishServerExceptionEvent(Exception ex) { - ApplicationEventPublisher applicationEventPublisher = getApplicationEventPublisher(); - if (applicationEventPublisher != null) { - applicationEventPublisher.publishEvent(new TcpConnectionServerExceptionEvent(this, ex)); - } + getApplicationEventPublisher().publishEvent(new TcpConnectionServerExceptionEvent(this, ex)); } protected void publishServerListeningEvent(int port) { final ApplicationEventPublisher eventPublisher = getApplicationEventPublisher(); - if (eventPublisher != null) { - final TcpConnectionServerListeningEvent event = new TcpConnectionServerListeningEvent(this, port); - TaskScheduler taskScheduler = getTaskScheduler(); - if (taskScheduler != null) { - try { - taskScheduler.schedule(() -> eventPublisher.publishEvent(event), Instant.now()); - } - catch (@SuppressWarnings("unused") TaskRejectedException e) { - eventPublisher.publishEvent(event); - } - } - else { - eventPublisher.publishEvent(event); - } + final TcpConnectionServerListeningEvent event = new TcpConnectionServerListeningEvent(this, port); + try { + getTaskScheduler().schedule(() -> eventPublisher.publishEvent(event), Instant.now()); + } + catch (@SuppressWarnings("unused") TaskRejectedException e) { + eventPublisher.publishEvent(event); } } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractTcpConnectionSupport.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractTcpConnectionSupport.java index f61d4ed50e0..997e1bef852 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractTcpConnectionSupport.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/AbstractTcpConnectionSupport.java @@ -20,6 +20,7 @@ * Base class for TCP Connection Support implementations. * * @author Gary Russell + * * @since 5.0 * */ @@ -47,7 +48,7 @@ public int getPushbackBufferSize() { } /** - * The size of the push back buffer; defaults to 1. + * The size of the push-back buffer; defaults to 1. * @param pushbackBufferSize the size. */ public void setPushbackBufferSize(int pushbackBufferSize) { diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactory.java index 99354883a35..c256f4d3d14 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactory.java @@ -23,13 +23,14 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.factory.DisposableBean; import org.springframework.core.serializer.Deserializer; import org.springframework.core.serializer.Serializer; import org.springframework.integration.ip.IpHeaders; import org.springframework.integration.support.AbstractIntegrationMessageBuilder; import org.springframework.integration.util.SimplePool; -import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.MessagingException; import org.springframework.messaging.support.ErrorMessage; @@ -139,7 +140,7 @@ public void setComponentName(String componentName) { } @Override - public String getComponentType() { + public @Nullable String getComponentType() { return this.targetConnectionFactory.getComponentType(); } @@ -229,7 +230,7 @@ public void setSoTrafficClass(int soTrafficClass) { } @Override - public String getHost() { + public @Nullable String getHost() { return this.targetConnectionFactory.getHost(); } @@ -239,7 +240,7 @@ public int getPort() { } @Override - public TcpSender getSender() { + public @Nullable TcpSender getSender() { return this.targetConnectionFactory.getSender(); } @@ -463,12 +464,12 @@ public String toString() { @Override public boolean onMessage(Message message) { Message modifiedMessage; + Object connectionId = message.getHeaders().get(IpHeaders.CONNECTION_ID); if (message instanceof ErrorMessage) { Map headers = new HashMap<>(message.getHeaders()); headers.put(IpHeaders.CONNECTION_ID, getConnectionId()); - if (headers.get(IpHeaders.ACTUAL_CONNECTION_ID) == null) { - headers.put(IpHeaders.ACTUAL_CONNECTION_ID, - message.getHeaders().get(IpHeaders.CONNECTION_ID)); + if (connectionId != null) { + headers.putIfAbsent(IpHeaders.ACTUAL_CONNECTION_ID, connectionId); } modifiedMessage = new ErrorMessage((Throwable) message.getPayload(), headers); } @@ -478,8 +479,7 @@ public boolean onMessage(Message message) { .fromMessage(message) .setHeader(IpHeaders.CONNECTION_ID, getConnectionId()); if (message.getHeaders().get(IpHeaders.ACTUAL_CONNECTION_ID) == null) { - messageBuilder.setHeader(IpHeaders.ACTUAL_CONNECTION_ID, - message.getHeaders().get(IpHeaders.CONNECTION_ID)); + messageBuilder.setHeader(IpHeaders.ACTUAL_CONNECTION_ID, connectionId); } modifiedMessage = messageBuilder.build(); } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/ClientModeConnectionManager.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/ClientModeConnectionManager.java index 5d653f739b3..6a5accd9e98 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/ClientModeConnectionManager.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/ClientModeConnectionManager.java @@ -22,6 +22,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; @@ -46,7 +47,7 @@ public class ClientModeConnectionManager implements Runnable { private final AbstractConnectionFactory clientConnectionFactory; - private volatile TcpConnection lastConnection; + private volatile @Nullable TcpConnection lastConnection; /** * @param clientConnectionFactory The connection factory. @@ -85,7 +86,8 @@ public void run() { } public boolean isConnected() { - return this.lastConnection != null && this.lastConnection.isOpen(); + TcpConnection lastConnectionToCheck = this.lastConnection; + return lastConnectionToCheck != null && lastConnectionToCheck.isOpen(); } } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/DefaultTcpNetConnectionSupport.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/DefaultTcpNetConnectionSupport.java index d8b7700691e..2017a96f665 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/DefaultTcpNetConnectionSupport.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/DefaultTcpNetConnectionSupport.java @@ -21,8 +21,9 @@ import java.io.PushbackInputStream; import java.net.Socket; +import org.jspecify.annotations.Nullable; + import org.springframework.context.ApplicationEventPublisher; -import org.springframework.lang.Nullable; /** * Default implementation of {@link TcpNetConnectionSupport}. @@ -37,7 +38,7 @@ public class DefaultTcpNetConnectionSupport extends AbstractTcpConnectionSupport @Override public TcpNetConnection createNewConnection(Socket socket, boolean server, boolean lookupHost, - @Nullable ApplicationEventPublisher applicationEventPublisher, String connectionFactoryName) { + @Nullable ApplicationEventPublisher applicationEventPublisher, @Nullable String connectionFactoryName) { if (isPushbackCapable()) { return new PushBackTcpNetConnection(socket, server, lookupHost, applicationEventPublisher, @@ -54,12 +55,12 @@ private static final class PushBackTcpNetConnection extends TcpNetConnection { private final String connectionId; - private volatile PushbackInputStream pushbackStream; + private volatile @Nullable PushbackInputStream pushbackStream; - private volatile InputStream wrapped; + private volatile @Nullable InputStream wrapped; PushBackTcpNetConnection(Socket socket, boolean server, boolean lookupHost, - @Nullable ApplicationEventPublisher applicationEventPublisher, String connectionFactoryName, + @Nullable ApplicationEventPublisher applicationEventPublisher, @Nullable String connectionFactoryName, int bufferSize) { super(socket, server, lookupHost, applicationEventPublisher, connectionFactoryName); diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/DefaultTcpNioConnectionSupport.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/DefaultTcpNioConnectionSupport.java index f8606c4c83a..de1cf5fc294 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/DefaultTcpNioConnectionSupport.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/DefaultTcpNioConnectionSupport.java @@ -20,8 +20,9 @@ import java.io.PushbackInputStream; import java.nio.channels.SocketChannel; +import org.jspecify.annotations.Nullable; + import org.springframework.context.ApplicationEventPublisher; -import org.springframework.lang.Nullable; /** * Implementation of {@link TcpNioConnectionSupport} for non-SSL @@ -37,7 +38,7 @@ public class DefaultTcpNioConnectionSupport extends AbstractTcpConnectionSupport @Override public TcpNioConnection createNewConnection(SocketChannel socketChannel, boolean server, boolean lookupHost, - @Nullable ApplicationEventPublisher applicationEventPublisher, String connectionFactoryName) { + @Nullable ApplicationEventPublisher applicationEventPublisher, @Nullable String connectionFactoryName) { if (isPushbackCapable()) { return new PushBackTcpNioConnection(socketChannel, server, lookupHost, applicationEventPublisher, @@ -55,9 +56,9 @@ private static final class PushBackTcpNioConnection extends TcpNioConnection { private final String connectionId; - private volatile PushbackInputStream pushbackStream; + private volatile @Nullable PushbackInputStream pushbackStream; - private volatile InputStream wrapped; + private volatile @Nullable InputStream wrapped; PushBackTcpNioConnection(SocketChannel socketChannel, boolean server, boolean lookupHost, @Nullable ApplicationEventPublisher applicationEventPublisher, @Nullable String connectionFactoryName, diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/DefaultTcpNioSSLConnectionSupport.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/DefaultTcpNioSSLConnectionSupport.java index 2fe21336bf5..e23532ff1f3 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/DefaultTcpNioSSLConnectionSupport.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/DefaultTcpNioSSLConnectionSupport.java @@ -26,15 +26,16 @@ import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLParameters; +import org.jspecify.annotations.Nullable; + import org.springframework.context.ApplicationEventPublisher; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** - * Implementation of {@link TcpNioConnectionSupport} for SSL - * NIO connections. + * Implementation of {@link TcpNioConnectionSupport} for SSL NIO connections. * * @author Gary Russell + * @author Artem Bilan * * @since 2.2 * @@ -76,7 +77,7 @@ public DefaultTcpNioSSLConnectionSupport(TcpSSLContextSupport sslContextSupport, */ @Override public TcpNioConnection createNewConnection(SocketChannel socketChannel, boolean server, boolean lookupHost, - @Nullable ApplicationEventPublisher applicationEventPublisher, String connectionFactoryName) { + @Nullable ApplicationEventPublisher applicationEventPublisher, @Nullable String connectionFactoryName) { SSLEngine sslEngine = this.sslContext.createSSLEngine(); postProcessSSLEngine(sslEngine); @@ -115,12 +116,12 @@ private static final class PushBackTcpNioSSLConnection extends TcpNioSSLConnecti private final String connectionId; - private volatile PushbackInputStream pushbackStream; + private volatile @Nullable PushbackInputStream pushbackStream; - private volatile InputStream wrapped; + private volatile @Nullable InputStream wrapped; PushBackTcpNioSSLConnection(SocketChannel socketChannel, boolean server, boolean lookupHost, - @Nullable ApplicationEventPublisher applicationEventPublisher, String connectionFactoryName, + @Nullable ApplicationEventPublisher applicationEventPublisher, @Nullable String connectionFactoryName, SSLEngine sslEngine, int bufferSize) { @@ -133,11 +134,13 @@ private static final class PushBackTcpNioSSLConnection extends TcpNioSSLConnecti protected InputStream inputStream() { InputStream wrappedStream = super.inputStream(); // It shouldn't be possible for the wrapped stream to change but, just in case... - if (this.pushbackStream == null || !wrappedStream.equals(this.wrapped)) { - this.pushbackStream = new PushbackInputStream(wrappedStream, this.pushbackBufferSize); + PushbackInputStream pushbackStreamToUse = this.pushbackStream; + if (pushbackStreamToUse == null || !wrappedStream.equals(this.wrapped)) { + pushbackStreamToUse = new PushbackInputStream(wrappedStream, this.pushbackBufferSize); + this.pushbackStream = pushbackStreamToUse; this.wrapped = wrappedStream; } - return this.pushbackStream; + return pushbackStreamToUse; } @Override diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/DefaultTcpSocketSupport.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/DefaultTcpSocketSupport.java index 08181fdea03..f62c88bfa20 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/DefaultTcpSocketSupport.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/DefaultTcpSocketSupport.java @@ -63,8 +63,7 @@ public void postProcessServerSocket(ServerSocket serverSocket) { */ @Override public void postProcessSocket(Socket socket) { - if (this.sslVerifyHost && socket instanceof SSLSocket) { - SSLSocket sslSocket = (SSLSocket) socket; + if (this.sslVerifyHost && socket instanceof SSLSocket sslSocket) { SSLParameters sslParameters = sslSocket.getSSLParameters(); // HTTPS works for any TCP connection. // It checks SAN (Subject Alternative Name) as well as CN. diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/FailoverClientConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/FailoverClientConnectionFactory.java index 273479717d1..302c99849e8 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/FailoverClientConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/FailoverClientConnectionFactory.java @@ -26,6 +26,8 @@ import javax.net.ssl.SSLSession; +import org.jspecify.annotations.Nullable; + import org.springframework.core.serializer.Deserializer; import org.springframework.core.serializer.Serializer; import org.springframework.integration.ip.IpHeaders; @@ -176,7 +178,7 @@ protected TcpConnectionSupport obtainConnection() throws InterruptedException { return failoverTcpConnection; } - private void closeRefreshedIfNecessary(FailoverTcpConnection sharedConnection, boolean refreshShared, + private void closeRefreshedIfNecessary(@Nullable FailoverTcpConnection sharedConnection, boolean refreshShared, FailoverTcpConnection failoverTcpConnection) { this.creationTime = System.currentTimeMillis(); @@ -184,6 +186,7 @@ private void closeRefreshedIfNecessary(FailoverTcpConnection sharedConnection, b * We may have simply wrapped the same connection in a new wrapper; don't close. */ if (refreshShared && this.closeOnRefresh + && sharedConnection != null && !sharedConnection.delegate.equals(failoverTcpConnection.delegate) && sharedConnection.isOpen()) { @@ -240,8 +243,10 @@ private final class FailoverTcpConnection extends TcpConnectionSupport implement private volatile Iterator factoryIterator; + @SuppressWarnings("NullAway.Init") private volatile AbstractClientConnectionFactory currentFactory; + @SuppressWarnings("NullAway.Init") volatile TcpConnectionSupport delegate; // NOSONAR visibility private volatile boolean open = true; @@ -370,7 +375,7 @@ public void send(Message message) { } @Override - public Object getPayload() { + public @Nullable Object getPayload() { return this.delegate.getPayload(); } @@ -395,12 +400,12 @@ public int getPort() { } @Override - public Object getDeserializerStateKey() { + public @Nullable Object getDeserializerStateKey() { return this.delegate.getDeserializerStateKey(); } @Override - public void registerSender(TcpSender sender) { + public void registerSender(@Nullable TcpSender sender) { this.delegate.registerSender(sender); } @@ -410,7 +415,7 @@ public String getConnectionId() { } @Override - public SocketInfo getSocketInfo() { + public @Nullable SocketInfo getSocketInfo() { return this.delegate.getSocketInfo(); } @@ -445,7 +450,7 @@ public void setSerializer(Serializer serializer) { } @Override - public SSLSession getSslSession() { + public @Nullable SSLSession getSslSession() { return this.delegate.getSslSession(); } @@ -461,7 +466,7 @@ public boolean onMessage(Message message) { AbstractIntegrationMessageBuilder messageBuilder = getMessageBuilderFactory() .fromMessage(message) - .setHeader(IpHeaders.CONNECTION_ID, this.getConnectionId()); + .setHeader(IpHeaders.CONNECTION_ID, getConnectionId()); if (message.getHeaders().get(IpHeaders.ACTUAL_CONNECTION_ID) == null) { messageBuilder.setHeader(IpHeaders.ACTUAL_CONNECTION_ID, message.getHeaders().get(IpHeaders.CONNECTION_ID)); diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/MessageConvertingTcpMessageMapper.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/MessageConvertingTcpMessageMapper.java index f5fc75a0fd8..4e812184df1 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/MessageConvertingTcpMessageMapper.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/MessageConvertingTcpMessageMapper.java @@ -16,10 +16,12 @@ package org.springframework.integration.ip.tcp.connection; +import java.io.Serial; import java.util.Map; +import org.jspecify.annotations.Nullable; + import org.springframework.integration.support.MutableMessageHeaders; -import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.converter.MessageConverter; @@ -27,7 +29,7 @@ /** * @author Gary Russell - * @author Artem Bilan + * @author Artem Bilan * * @since 3.0 * @@ -42,12 +44,13 @@ public MessageConvertingTcpMessageMapper(MessageConverter messageConverter) { } @Override - public Message toMessage(TcpConnection connection, @Nullable Map headers) { + public @Nullable Message toMessage(TcpConnection connection, @Nullable Map headers) { Object data = connection.getPayload(); if (data != null) { MessageHeaders messageHeaders = new MutableMessageHeaders(null, MessageHeaders.ID_VALUE_NONE, -1L) { + @Serial private static final long serialVersionUID = 3084692953798643018L; }; @@ -70,7 +73,7 @@ public Message toMessage(TcpConnection connection, @Nullable Map message) { + public @Nullable Object fromMessage(Message message) { return this.messageConverter.fromMessage(message, Object.class); } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnection.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnection.java index 91617859a31..2d7640da5e6 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnection.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnection.java @@ -20,9 +20,10 @@ import javax.net.ssl.SSLSession; +import org.jspecify.annotations.Nullable; + import org.springframework.core.serializer.Deserializer; import org.springframework.core.serializer.Serializer; -import org.springframework.lang.Nullable; import org.springframework.messaging.Message; /** @@ -132,6 +133,7 @@ public interface TcpConnection extends Runnable { * should override and delegate to the actual TcpConnection. * @since 4.3 */ + @Nullable SocketInfo getSocketInfo(); /** diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionCloseEvent.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionCloseEvent.java index 90796f9f141..64a1b9987d7 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionCloseEvent.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionCloseEvent.java @@ -16,6 +16,8 @@ package org.springframework.integration.ip.tcp.connection; +import java.io.Serial; + /** * @author Gary Russell * @since 3.0 @@ -23,6 +25,7 @@ */ public class TcpConnectionCloseEvent extends TcpConnectionEvent { + @Serial private static final long serialVersionUID = 7237316997596598287L; public TcpConnectionCloseEvent(TcpConnection connection, String connectionFactoryName) { diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionExceptionEvent.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionExceptionEvent.java index 31bb9de7c38..b844fd43d45 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionExceptionEvent.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionExceptionEvent.java @@ -16,18 +16,24 @@ package org.springframework.integration.ip.tcp.connection; +import java.io.Serial; + /** * ApplicationEvent representing exceptions on a {@link TcpConnection}. + * * @author Gary Russell + * * @since 3.0 * */ public class TcpConnectionExceptionEvent extends TcpConnectionEvent { + @Serial private static final long serialVersionUID = 1335560439854592185L; public TcpConnectionExceptionEvent(TcpConnection connection, String connectionFactoryName, Throwable cause) { + super(connection, connectionFactoryName, cause); } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionFailedCorrelationEvent.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionFailedCorrelationEvent.java index f60a03fe6ef..e47f153930b 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionFailedCorrelationEvent.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionFailedCorrelationEvent.java @@ -16,6 +16,10 @@ package org.springframework.integration.ip.tcp.connection; +import java.io.Serial; + +import org.jspecify.annotations.Nullable; + import org.springframework.integration.ip.event.IpIntegrationEvent; import org.springframework.messaging.MessagingException; @@ -24,21 +28,24 @@ * connection; the cause is a messaging exception with the failed message. * * @author Gary Russell + * @author Artem Bilan + * * @since 4.2 * */ public class TcpConnectionFailedCorrelationEvent extends IpIntegrationEvent { + @Serial private static final long serialVersionUID = -7460880274740273542L; - private final String connectionId; + private final @Nullable String connectionId; - public TcpConnectionFailedCorrelationEvent(Object source, String connectionId, MessagingException cause) { + public TcpConnectionFailedCorrelationEvent(Object source, @Nullable String connectionId, MessagingException cause) { super(source, cause); this.connectionId = connectionId; } - public String getConnectionId() { + public @Nullable String getConnectionId() { return this.connectionId; } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionFailedEvent.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionFailedEvent.java index c7dbfae4230..29bb04a6142 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionFailedEvent.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionFailedEvent.java @@ -16,6 +16,8 @@ package org.springframework.integration.ip.tcp.connection; +import java.io.Serial; + import org.springframework.integration.ip.event.IpIntegrationEvent; /** @@ -28,6 +30,7 @@ */ public class TcpConnectionFailedEvent extends IpIntegrationEvent { + @Serial private static final long serialVersionUID = -7460880274740273542L; public TcpConnectionFailedEvent(Object source, Throwable cause) { diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionInterceptorFactoryChain.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionInterceptorFactoryChain.java index 87f7f7dca6f..504b5b24bfe 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionInterceptorFactoryChain.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionInterceptorFactoryChain.java @@ -18,20 +18,20 @@ import java.util.Arrays; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; /** * @author Gary Russell * @author Artem Bilan + * * @since 2.0 * */ public class TcpConnectionInterceptorFactoryChain { - private TcpConnectionInterceptorFactory[] interceptorFactories; + private TcpConnectionInterceptorFactory @Nullable [] interceptorFactories; - @Nullable - public TcpConnectionInterceptorFactory[] getInterceptorFactories() { + public TcpConnectionInterceptorFactory @Nullable [] getInterceptorFactories() { return this.interceptorFactories; //NOSONAR } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionInterceptorSupport.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionInterceptorSupport.java index 1f809ec02f2..ef4c57b689e 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionInterceptorSupport.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionInterceptorSupport.java @@ -23,10 +23,11 @@ import javax.net.ssl.SSLSession; +import org.jspecify.annotations.Nullable; + import org.springframework.context.ApplicationEventPublisher; import org.springframework.core.serializer.Deserializer; import org.springframework.core.serializer.Serializer; -import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.support.ErrorMessage; @@ -45,13 +46,14 @@ public abstract class TcpConnectionInterceptorSupport extends TcpConnectionSuppo private final Lock lock = new ReentrantLock(); + @SuppressWarnings("NullAway.Init") private TcpConnectionSupport theConnection; - private TcpListener tcpListener; + private @Nullable TcpListener tcpListener; private boolean realSender; - private List interceptedSenders; + private @Nullable List interceptedSenders; private boolean removed; @@ -73,7 +75,7 @@ public boolean isOpen() { } @Override - public Object getPayload() { + public @Nullable Object getPayload() { return this.theConnection.getPayload(); } @@ -93,18 +95,18 @@ public int getPort() { } @Override - public Object getDeserializerStateKey() { + public @Nullable Object getDeserializerStateKey() { return this.theConnection.getDeserializerStateKey(); } @Override - public void registerListener(TcpListener listener) { + public void registerListener(@Nullable TcpListener listener) { this.tcpListener = listener; this.theConnection.registerListener(this); } @Override - public void registerSender(TcpSender sender) { + public void registerSender(@Nullable TcpSender sender) { this.theConnection.registerSender(this); } @@ -112,12 +114,11 @@ public void registerSender(TcpSender sender) { public void registerSenders(List sendersToRegister) { this.interceptedSenders = sendersToRegister; if (!sendersToRegister.isEmpty()) { - if (!(sendersToRegister.get(0) instanceof TcpConnectionInterceptorSupport)) { + if (!(sendersToRegister.get(0) instanceof TcpConnectionInterceptorSupport interceptorToUse)) { this.realSender = true; } else { - this.realSender = ((TcpConnectionInterceptorSupport) this.interceptedSenders.get(0)) - .hasRealSender(); + this.realSender = interceptorToUse.hasRealSender(); } } if (this.theConnection instanceof TcpConnectionInterceptorSupport) { @@ -143,7 +144,7 @@ public String getConnectionId() { } @Override - public SocketInfo getSocketInfo() { + public @Nullable SocketInfo getSocketInfo() { return this.theConnection.getSocketInfo(); } @@ -188,7 +189,7 @@ public boolean isServer() { } @Override - public SSLSession getSslSession() { + public @Nullable SSLSession getSslSession() { return this.theConnection.getSslSession(); } @@ -230,8 +231,7 @@ public void setTheConnection(TcpConnectionSupport theConnection) { * @return the listener */ @Override - @Nullable - public TcpListener getListener() { + public @Nullable TcpListener getListener() { return this.tcpListener; } @@ -254,7 +254,7 @@ public void removeDeadConnection(TcpConnection connection) { tcpConnectionInterceptorSupport.removeDeadConnection(this); } TcpSender sender = getSender(); - if (sender != null && !(sender instanceof TcpConnectionInterceptorSupport)) { + if (sender != null && this.interceptedSenders != null && !(sender instanceof TcpConnectionInterceptorSupport)) { this.interceptedSenders.forEach(snder -> snder.removeDeadConnection(connection)); } } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionOpenEvent.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionOpenEvent.java index f1ae0172d80..a7cb3bdb91d 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionOpenEvent.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionOpenEvent.java @@ -16,6 +16,8 @@ package org.springframework.integration.ip.tcp.connection; +import java.io.Serial; + /** * @author Gary Russell * @since 3.0 @@ -23,6 +25,7 @@ */ public class TcpConnectionOpenEvent extends TcpConnectionEvent { + @Serial private static final long serialVersionUID = 7237316997596598287L; public TcpConnectionOpenEvent(TcpConnection connection, String connectionFactoryName) { diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionServerListeningEvent.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionServerListeningEvent.java index c3a15f49a35..2b1cd9a6d1f 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionServerListeningEvent.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionServerListeningEvent.java @@ -21,7 +21,7 @@ /** * {@link IpIntegrationEvent} emitted when a server begins listening. Useful * when the configured port is zero and the operating system chooses the port. - * Also useful to avoid polling the {@code isListening()} if you need to wait + * Also, useful to avoid polling the {@code isListening()} if you need to wait * before starting some other process to connect to the socket. * * @author Gary Russell diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionSupport.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionSupport.java index d7b46811c57..babe1ebf33c 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionSupport.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpConnectionSupport.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -30,13 +31,13 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.context.ApplicationEventPublisher; import org.springframework.core.serializer.Deserializer; import org.springframework.core.serializer.Serializer; import org.springframework.integration.ip.IpHeaders; import org.springframework.integration.ip.tcp.serializer.AbstractByteArraySerializer; -import org.springframework.lang.Nullable; import org.springframework.messaging.MessagingException; import org.springframework.messaging.support.ErrorMessage; import org.springframework.util.Assert; @@ -63,29 +64,30 @@ public abstract class TcpConnectionSupport implements TcpConnection { private final AtomicLong sequence = new AtomicLong(); - private final ApplicationEventPublisher applicationEventPublisher; + private final @Nullable ApplicationEventPublisher applicationEventPublisher; private final AtomicBoolean closePublished = new AtomicBoolean(); private final AtomicBoolean exceptionSent = new AtomicBoolean(); - private final SocketInfo socketInfo; + private final @Nullable SocketInfo socketInfo; private final List senders = Collections.synchronizedList(new ArrayList<>()); - @SuppressWarnings("rawtypes") + @SuppressWarnings({"rawtypes", "NullAway.Init"}) private Deserializer deserializer; - @SuppressWarnings("rawtypes") + @SuppressWarnings({"rawtypes", "NullAway.Init"}) private Serializer serializer; + @SuppressWarnings("NullAway.Init") private TcpMessageMapper mapper; - private TcpListener listener; + private @Nullable TcpListener listener; - private volatile TcpListener testListener; + private volatile @Nullable TcpListener testListener; - private String connectionId; + private final String connectionId; private String hostName = "unknown"; @@ -99,7 +101,7 @@ public abstract class TcpConnectionSupport implements TcpConnection { private boolean wrapped; - private TcpConnectionSupport wrapper; + private @Nullable TcpConnectionSupport wrapper; /* * This boolean is to avoid looking for a temporary listener when not needed @@ -118,6 +120,7 @@ public TcpConnectionSupport(@Nullable ApplicationEventPublisher applicationEvent this.server = false; this.applicationEventPublisher = applicationEventPublisher; this.socketInfo = null; + this.connectionId = UUID.randomUUID().toString(); } /** @@ -150,7 +153,7 @@ public TcpConnectionSupport(Socket socket, boolean server, boolean lookupHost, } int port = socket.getPort(); int localPort = socket.getLocalPort(); - this.connectionId = this.hostName + ":" + port + ":" + localPort + ":" + UUID.randomUUID().toString(); + this.connectionId = this.hostName + ":" + port + ":" + localPort + ":" + UUID.randomUUID(); this.applicationEventPublisher = applicationEventPublisher; if (connectionFactoryName != null) { this.connectionFactoryName = connectionFactoryName; @@ -187,16 +190,11 @@ public void close() { */ protected void closeConnection(boolean isException) { TcpListener tcpListener = getListener(); - if (!(tcpListener instanceof TcpConnectionInterceptor)) { + if (!(tcpListener instanceof TcpConnectionInterceptor outerListener)) { close(); } else { - TcpConnectionInterceptor outerListener = (TcpConnectionInterceptor) tcpListener; - while (outerListener.getListener() instanceof TcpConnectionInterceptor) { - TcpConnectionInterceptor nextListener = (TcpConnectionInterceptor) outerListener.getListener(); - if (nextListener == null) { - break; - } + while (outerListener.getListener() instanceof TcpConnectionInterceptor nextListener) { outerListener = nextListener; } outerListener.close(); @@ -219,12 +217,8 @@ public TcpMessageMapper getMapper() { * @param mapper the mapper to set */ public void setMapper(TcpMessageMapper mapper) { - Assert.notNull(mapper, this.getClass().getName() + " Mapper may not be null"); + Assert.notNull(mapper, getClass().getName() + " Mapper may not be null"); this.mapper = mapper; - if (this.serializer != null && - !(this.serializer instanceof AbstractByteArraySerializer)) { - mapper.setStringToBytes(false); - } } /** @@ -295,14 +289,14 @@ public void registerTestListener(TcpListener tListener) { } /** - * Set whether or not automatic or manual registration of the {@link TcpListener} is to be + * Set whether automatic or manual registration of the {@link TcpListener} is to be * used. (Default automatic). When manual registration is in place, incoming messages will * be delayed until the listener is registered. * @since 1.4.5 */ public void enableManualListenerRegistration() { this.manualListenerRegistration = true; - this.listener = message -> getListener().onMessage(message); + this.listener = message -> Objects.requireNonNull(getListener()).onMessage(message); } /** @@ -336,8 +330,7 @@ public void registerSenders(List sendersToRegister) { * @return the listener */ @Override - @Nullable - public TcpListener getListener() { + public @Nullable TcpListener getListener() { if (this.needsTest && this.testListener != null) { this.needsTest = false; return this.testListener; @@ -369,8 +362,7 @@ private void waitForListenerRegistration() { /** * @return the first sender, if present. */ - @Nullable - public TcpSender getSender() { + public @Nullable TcpSender getSender() { return !this.senders.isEmpty() ? this.senders.get(0) : null; } @@ -412,7 +404,7 @@ public String getConnectionId() { * @since 4.2.5 */ @Override - public SocketInfo getSocketInfo() { + public @Nullable SocketInfo getSocketInfo() { return this.socketInfo; } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpMessageMapper.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpMessageMapper.java index 68084571c8b..001c0c23479 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpMessageMapper.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpMessageMapper.java @@ -22,6 +22,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jspecify.annotations.Nullable; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; @@ -36,7 +37,6 @@ import org.springframework.integration.support.MessageBuilderFactory; import org.springframework.integration.support.MutableMessageHeaders; import org.springframework.integration.support.utils.IntegrationUtils; -import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; import org.springframework.util.Assert; @@ -82,9 +82,10 @@ public class TcpMessageMapper implements private boolean addContentTypeHeader; + @SuppressWarnings("NullAway.Init") private BeanFactory beanFactory; - private BytesMessageMapper bytesMessageMapper; + private @Nullable BytesMessageMapper bytesMessageMapper; /** * Set the charset to use when converting outbound String messages to {@code byte[]}. @@ -162,9 +163,7 @@ public void setBytesMessageMapper(BytesMessageMapper bytesMessageMapper) { protected MessageBuilderFactory getMessageBuilderFactory() { if (!this.messageBuilderFactorySet) { - if (this.beanFactory != null) { - this.messageBuilderFactory = IntegrationUtils.getMessageBuilderFactory(this.beanFactory); - } + this.messageBuilderFactory = IntegrationUtils.getMessageBuilderFactory(this.beanFactory); this.messageBuilderFactorySet = true; } return this.messageBuilderFactory; @@ -172,7 +171,7 @@ protected MessageBuilderFactory getMessageBuilderFactory() { @SuppressWarnings("unchecked") @Override - public Message toMessage(TcpConnection connection, @Nullable Map headers) { + public @Nullable Message toMessage(TcpConnection connection, @Nullable Map headers) { Message message = null; Object payload = connection.getPayload(); if (payload != null) { @@ -239,13 +238,12 @@ protected final void addCustomHeaders(TcpConnection connection, MessageHeaders m * @param connection the connection. * @return A Map of {@code } headers to be added to the message. */ - @Nullable - protected Map supplyCustomHeaders(TcpConnection connection) { + protected @Nullable Map supplyCustomHeaders(TcpConnection connection) { return null; } @Override - public Object fromMessage(Message message) { + public @Nullable Object fromMessage(Message message) { if (this.bytesMessageMapper != null) { return this.bytesMessageMapper.fromMessage(message); } @@ -259,7 +257,7 @@ public Object fromMessage(Message message) { * Extracts the payload as a byte array. */ private byte[] getPayloadAsBytes(Message message) { - byte[] bytes = null; + byte[] bytes; Object payload = message.getPayload(); if (payload instanceof byte[] castBytes) { bytes = castBytes; diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetClientConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetClientConnectionFactory.java index e93b8c35782..b6a5b226d5b 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetClientConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetClientConnectionFactory.java @@ -51,7 +51,9 @@ public TcpNetClientConnectionFactory(String host, int port) { @Override protected TcpConnectionSupport buildNewConnection() { try { - Socket socket = createSocket(getHost(), getPort()); + String host = getHost(); + Assert.notNull(host, "The 'host' must not be null for TCP/IP client."); + Socket socket = createSocket(host, getPort()); setSocketAttributes(socket); TcpConnectionSupport connection = this.tcpNetConnectionSupport.createNewConnection(socket, false, isLookupHost(), diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetConnection.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetConnection.java index fbbb324609f..7ea942cc352 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetConnection.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetConnection.java @@ -31,10 +31,11 @@ import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; +import org.jspecify.annotations.Nullable; + import org.springframework.context.ApplicationEventPublisher; import org.springframework.core.serializer.Serializer; import org.springframework.integration.ip.tcp.serializer.SoftEndOfStreamException; -import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.MessagingException; import org.springframework.scheduling.SchedulingAwareRunnable; @@ -57,7 +58,7 @@ public class TcpNetConnection extends TcpConnectionSupport implements Scheduling private final Socket socket; - private volatile OutputStream socketOutputStream; + private volatile @Nullable OutputStream socketOutputStream; private volatile long lastRead = System.currentTimeMillis(); @@ -76,7 +77,7 @@ public class TcpNetConnection extends TcpConnectionSupport implements Scheduling * during event publishing, may be null, in which case "unknown" will be used. */ public TcpNetConnection(Socket socket, boolean server, boolean lookupHost, - @Nullable ApplicationEventPublisher applicationEventPublisher, String connectionFactoryName) { + @Nullable ApplicationEventPublisher applicationEventPublisher, @Nullable String connectionFactoryName) { super(socket, server, lookupHost, applicationEventPublisher, connectionFactoryName); this.socket = socket; @@ -111,16 +112,18 @@ public boolean isOpen() { public void send(Message message) { this.lock.lock(); try { - if (this.socketOutputStream == null) { + OutputStream socketOutputStreamToUse = this.socketOutputStream; + if (socketOutputStreamToUse == null) { int writeBufferSize = this.socket.getSendBufferSize(); - this.socketOutputStream = new BufferedOutputStream(this.socket.getOutputStream(), - writeBufferSize > 0 ? writeBufferSize : 8192); // NOSONAR magic number + socketOutputStreamToUse = new BufferedOutputStream(this.socket.getOutputStream(), + writeBufferSize > 0 ? writeBufferSize : 8192); + this.socketOutputStream = socketOutputStreamToUse; } Object object = getMapper().fromMessage(message); - Assert.state(object != null, "Mapper mapped the message to 'null'."); + Assert.state(object != null, () -> "The mapper returned null for message: " + message); this.lastSend = System.currentTimeMillis(); - ((Serializer) getSerializer()).serialize(object, this.socketOutputStream); - this.socketOutputStream.flush(); + ((Serializer) getSerializer()).serialize(object, socketOutputStreamToUse); + socketOutputStreamToUse.flush(); } catch (Exception e) { MessagingException mex = new MessagingException(message, "Send Failed", e); @@ -160,8 +163,7 @@ public int getPort() { } @Override - @Nullable - public Object getDeserializerStateKey() { + public @Nullable Object getDeserializerStateKey() { try { return inputStream(); } @@ -171,8 +173,7 @@ public Object getDeserializerStateKey() { } @Override - @Nullable - public SSLSession getSslSession() { + public @Nullable SSLSession getSslSession() { if (this.socket instanceof SSLSocket sslSocket) { return sslSocket.getSession(); } @@ -250,6 +251,9 @@ private boolean receiveAndProcessMessage() { protected boolean handleReadException(Exception exception) { Exception e = exception instanceof UncheckedIOException ? (Exception) exception.getCause() : exception; + if (e == null) { + e = exception; + } if (checkTimeout(e)) { boolean readErrorOnClose = !isNoReadErrorOnClose(); closeConnection(true); @@ -279,7 +283,7 @@ private boolean checkTimeout(Exception e) { long now = System.currentTimeMillis(); try { int soTimeout = this.socket.getSoTimeout(); - if (now - this.lastSend < soTimeout && now - this.lastRead < soTimeout * 2) { + if (now - this.lastSend < soTimeout && now - this.lastRead < soTimeout * 2L) { doClose = false; } if (!doClose && logger.isDebugEnabled()) { diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetConnectionSupport.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetConnectionSupport.java index ee6f5a9dbf8..56f53e730ca 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetConnectionSupport.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetConnectionSupport.java @@ -18,8 +18,9 @@ import java.net.Socket; +import org.jspecify.annotations.Nullable; + import org.springframework.context.ApplicationEventPublisher; -import org.springframework.lang.Nullable; /** * Used by NET connection factories to instantiate a {@link TcpNetConnection} object. @@ -48,6 +49,6 @@ public interface TcpNetConnectionSupport { TcpNetConnection createNewConnection(Socket socket, boolean server, boolean lookupHost, @Nullable ApplicationEventPublisher applicationEventPublisher, - String connectionFactoryName); + @Nullable String connectionFactoryName); } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetServerConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetServerConnectionFactory.java index 79ec55d4aa1..61575ac26f5 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetServerConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNetServerConnectionFactory.java @@ -26,7 +26,8 @@ import javax.net.ServerSocketFactory; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; /** @@ -46,7 +47,7 @@ public class TcpNetServerConnectionFactory extends AbstractServerConnectionFacto private TcpNetConnectionSupport tcpNetConnectionSupport = new DefaultTcpNetConnectionSupport(); - private volatile ServerSocket serverSocket; + private volatile @Nullable ServerSocket serverSocket; /** * Listens for incoming connections on the port. @@ -72,10 +73,10 @@ public int getPort() { } @Override - @Nullable - public SocketAddress getServerSocketAddress() { - if (this.serverSocket != null) { - return this.serverSocket.getLocalSocketAddress(); + public @Nullable SocketAddress getServerSocketAddress() { + ServerSocket serverSocketToUse = this.serverSocket; + if (serverSocketToUse != null) { + return serverSocketToUse.getLocalSocketAddress(); } else { return null; @@ -160,12 +161,13 @@ private void acceptConnectionAndExecute() throws IOException { * Not fatal. */ try { - if (this.serverSocket == null) { + ServerSocket serverSocketToUse = this.serverSocket; + if (serverSocketToUse == null) { logger.debug(() -> this + " stopped before accept"); throw new IOException(this + " stopped before accept"); } else { - socket = this.serverSocket.accept(); + socket = serverSocketToUse.accept(); } } catch (@SuppressWarnings("unused") SocketTimeoutException ste) { @@ -232,11 +234,12 @@ protected ServerSocket createServerSocket(int port, int backlog, @Nullable InetA @Override public void stop() { - if (this.serverSocket == null) { + ServerSocket serverSocketToClose = this.serverSocket; + if (serverSocketToClose == null) { return; } try { - this.serverSocket.close(); + serverSocketToClose.close(); } catch (@SuppressWarnings("unused") IOException e) { } @@ -247,7 +250,7 @@ public void stop() { /** * @return the serverSocket */ - protected ServerSocket getServerSocket() { + protected @Nullable ServerSocket getServerSocket() { return this.serverSocket; } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioClientConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioClientConnectionFactory.java index 09ea943593d..0f103bd6aae 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioClientConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioClientConnectionFactory.java @@ -26,10 +26,13 @@ import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.Map; +import java.util.Objects; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; +import org.jspecify.annotations.Nullable; + import org.springframework.scheduling.SchedulingAwareRunnable; import org.springframework.util.Assert; @@ -56,7 +59,7 @@ public class TcpNioClientConnectionFactory extends private TcpNioConnectionSupport tcpNioConnectionSupport = new DefaultTcpNioConnectionSupport(); - private volatile Selector selector; + private volatile @Nullable Selector selector; /** * Creates a TcpNioClientConnectionFactory for connections to the host and port. @@ -111,7 +114,7 @@ protected TcpConnectionSupport buildNewConnection() { this.channelMap.put(socketChannel, connection); wrappedConnection.publishConnectionOpenEvent(); this.newChannels.add(socketChannel); - this.selector.wakeup(); + Objects.requireNonNull(this.selector).wakeup(); return wrappedConnection; } catch (IOException e) { @@ -168,9 +171,10 @@ public boolean isLongLived() { @Override public void stop() { - if (this.selector != null) { + Selector selectorToClose = this.selector; + if (selectorToClose != null) { try { - this.selector.close(); + selectorToClose.close(); } catch (Exception ex) { logger.error(ex, "Error closing selector"); @@ -198,9 +202,10 @@ public void start() { public void run() { logger.debug(() -> "Read selector running for connections to " + getHost() + ':' + getPort()); try { - this.selector = Selector.open(); + Selector selectorToUse = Selector.open(); + this.selector = selectorToUse; while (isActive()) { - processSelectorWhileActive(); + processSelectorWhileActive(selectorToUse); } } catch (ClosedSelectorException cse) { @@ -215,7 +220,7 @@ public void run() { logger.debug(() -> "Read selector exiting for connections to " + getHost() + ':' + getPort()); } - private void processSelectorWhileActive() throws IOException { + private void processSelectorWhileActive(Selector selector) throws IOException { SocketChannel newChannel; int soTimeout = getSoTimeout(); int selectionCount = 0; @@ -224,20 +229,20 @@ private void processSelectorWhileActive() throws IOException { if (!getDelayedReads().isEmpty() && (timeout == 0 || getReadDelay() < timeout)) { timeout = getReadDelay(); } - selectionCount = this.selector.select(timeout); + selectionCount = selector.select(timeout); } catch (@SuppressWarnings("unused") CancelledKeyException cke) { logger.debug("CancelledKeyException during Selector.select()"); } while ((newChannel = this.newChannels.poll()) != null) { try { - newChannel.register(this.selector, SelectionKey.OP_READ, this.channelMap.get(newChannel)); + newChannel.register(selector, SelectionKey.OP_READ, this.channelMap.get(newChannel)); } catch (@SuppressWarnings("unused") ClosedChannelException cce) { logger.debug("Channel closed before registering with selector for reading"); } } - processNioSelections(selectionCount, this.selector, null, this.channelMap); + processNioSelections(selectionCount, selector, null, this.channelMap); } /** diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioConnection.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioConnection.java index 0863a014f25..26df6155c1a 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioConnection.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioConnection.java @@ -28,6 +28,7 @@ import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.Arrays; +import java.util.Objects; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; @@ -42,11 +43,12 @@ import javax.net.ssl.SSLSession; +import org.jspecify.annotations.Nullable; + import org.springframework.context.ApplicationEventPublisher; import org.springframework.core.serializer.Serializer; import org.springframework.integration.ip.tcp.serializer.SoftEndOfStreamException; import org.springframework.integration.util.CompositeExecutor; -import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.MessagingException; import org.springframework.util.Assert; @@ -93,11 +95,11 @@ public class TcpNioConnection extends TcpConnectionSupport { private long pipeTimeout = DEFAULT_PIPE_TIMEOUT; - private volatile OutputStream bufferedOutputStream; + private volatile @Nullable OutputStream bufferedOutputStream; - private volatile CompositeExecutor taskExecutor; + private volatile @Nullable CompositeExecutor taskExecutor; - private volatile ByteBuffer rawBuffer; + private volatile @Nullable ByteBuffer rawBuffer; private volatile long lastRead; @@ -105,7 +107,7 @@ public class TcpNioConnection extends TcpConnectionSupport { private volatile boolean writingToPipe; - private volatile CountDownLatch writingLatch; + private volatile @Nullable CountDownLatch writingLatch; private volatile boolean timedOut; @@ -166,16 +168,18 @@ public void send(Message message) { this.socketChannelMonitor.lock(); try { try { - if (this.bufferedOutputStream == null) { + OutputStream bufferedOutputStreamToUse = this.bufferedOutputStream; + if (bufferedOutputStreamToUse == null) { int writeBufferSize = this.socketChannel.socket().getSendBufferSize(); - this.bufferedOutputStream = new BufferedOutputStream(getChannelOutputStream(), - writeBufferSize > 0 ? writeBufferSize : 8192); // NOSONAR + bufferedOutputStreamToUse = new BufferedOutputStream(getChannelOutputStream(), + writeBufferSize > 0 ? writeBufferSize : 8192); + this.bufferedOutputStream = bufferedOutputStreamToUse; } Object object = getMapper().fromMessage(message); - Assert.state(object != null, "Mapper mapped the message to 'null'."); + Assert.state(object != null, () -> "The mapper returned null for message: " + message); this.lastSend = System.currentTimeMillis(); - ((Serializer) getSerializer()).serialize(object, this.bufferedOutputStream); - this.bufferedOutputStream.flush(); + ((Serializer) getSerializer()).serialize(object, bufferedOutputStreamToUse); + bufferedOutputStreamToUse.flush(); } catch (Exception e) { MessagingException mex = new MessagingException(message, "Send Failed", e); @@ -263,7 +267,7 @@ public void run() { // to assemble the next message, while we send ours this.executionControl.incrementAndGet(); try { - this.taskExecutor.execute2(this); + Objects.requireNonNull(this.taskExecutor).execute2(this); } catch (@SuppressWarnings(UNUSED) RejectedExecutionException e) { this.executionControl.decrementAndGet(); @@ -367,8 +371,7 @@ private boolean dataAvailable() { * @return The Message or null if no data is available. * @throws IOException an IO exception */ - @Nullable - private Message convert() throws IOException { + private @Nullable Message convert() throws IOException { this.lock.lock(); try { if (logger.isTraceEnabled()) { @@ -376,9 +379,10 @@ private Message convert() throws IOException { getConnectionId() + " checking data avail (convert): " + this.channelInputStream.available() + " pending: " + (this.writingToPipe)); } - if (this.channelInputStream.available() <= 0) { + CountDownLatch writingLatchToUse = this.writingLatch; + if (this.channelInputStream.available() <= 0 && writingLatchToUse != null) { try { - if (this.writingLatch.await(SIXTY, TimeUnit.SECONDS)) { + if (writingLatchToUse.await(SIXTY, TimeUnit.SECONDS)) { if (this.channelInputStream.available() <= 0) { return null; } @@ -402,10 +406,8 @@ private Message convert() throws IOException { logger.debug("Closing socket after timeout " + getConnectionId()); } } - else { - if (!(e instanceof SoftEndOfStreamException)) { // NOSONAR instanceof - throw e; - } + else if (!(e instanceof SoftEndOfStreamException)) { // NOSONAR instanceof + throw e; } return null; } @@ -437,11 +439,14 @@ private void sendToChannel(Message message) { } private void doRead() throws IOException { - if (this.rawBuffer == null) { - this.rawBuffer = allocate(MAX_MESSAGE_SIZE); + ByteBuffer rawBufferToUse = this.rawBuffer; + if (rawBufferToUse == null) { + rawBufferToUse = allocate(MAX_MESSAGE_SIZE); + this.rawBuffer = rawBufferToUse; } - this.writingLatch = new CountDownLatch(1); + CountDownLatch writingLatchToUse = new CountDownLatch(1); + this.writingLatch = writingLatchToUse; this.writingToPipe = true; try { if (this.taskExecutor == null) { @@ -452,32 +457,32 @@ private void doRead() throws IOException { checkForAssembler(); if (logger.isTraceEnabled()) { - logger.trace("Before read: " + this.rawBuffer.position() + '/' + this.rawBuffer.limit()); + logger.trace("Before read: " + rawBufferToUse.position() + '/' + rawBufferToUse.limit()); } - int len = this.socketChannel.read(this.rawBuffer); + int len = this.socketChannel.read(rawBufferToUse); if (len < 0) { this.writingToPipe = false; closeConnection(true); } if (logger.isTraceEnabled()) { - logger.trace("After read: " + this.rawBuffer.position() + '/' + this.rawBuffer.limit()); + logger.trace("After read: " + rawBufferToUse.position() + '/' + rawBufferToUse.limit()); } - this.rawBuffer.flip(); + rawBufferToUse.flip(); if (logger.isTraceEnabled()) { - logger.trace("After flip: " + this.rawBuffer.position() + '/' + this.rawBuffer.limit()); + logger.trace("After flip: " + rawBufferToUse.position() + '/' + rawBufferToUse.limit()); } if (logger.isDebugEnabled()) { - logger.debug("Read " + this.rawBuffer.limit() + " into raw buffer"); + logger.debug("Read " + rawBufferToUse.limit() + " into raw buffer"); } - sendToPipe(this.rawBuffer); + sendToPipe(rawBufferToUse); } - catch (IOException e) { - publishConnectionExceptionEvent(e); - throw e; + catch (IOException ex) { + publishConnectionExceptionEvent(ex); + throw ex; } finally { this.writingToPipe = false; - this.writingLatch.countDown(); + writingLatchToUse.countDown(); } } @@ -500,7 +505,7 @@ private void checkForAssembler() { logger.debug(getConnectionId() + " Running an assembler"); } try { - this.taskExecutor.execute2(this); + Objects.requireNonNull(this.taskExecutor).execute2(this); } catch (RejectedExecutionException e) { this.executionControl.decrementAndGet(); @@ -626,9 +631,9 @@ public void shutdownOutput() throws IOException { * OutputStream to wrap a SocketChannel; implements timeout on write. * */ - class ChannelOutputStream extends OutputStream { + protected class ChannelOutputStream extends OutputStream { - private Selector selector; + private @Nullable Selector selector; private int soTimeout; @@ -673,17 +678,19 @@ protected void doWrite(ByteBuffer buffer) throws IOException { if (remaining == 0) { return; } - if (this.selector == null) { - this.selector = Selector.open(); + Selector selectorToUse = this.selector; + if (selectorToUse == null) { + selectorToUse = Selector.open(); + this.selector = selectorToUse; this.soTimeout = TcpNioConnection.this.socketChannel.socket().getSoTimeout(); } - TcpNioConnection.this.socketChannel.register(this.selector, SelectionKey.OP_WRITE); + TcpNioConnection.this.socketChannel.register(selectorToUse, SelectionKey.OP_WRITE); while (remaining > 0) { - int selectionCount = this.selector.select(this.soTimeout); + int selectionCount = selectorToUse.select(this.soTimeout); if (selectionCount == 0) { throw new SocketTimeoutException("Timeout on write"); } - this.selector.selectedKeys().clear(); + selectorToUse.selectedKeys().clear(); TcpNioConnection.this.socketChannel.write(buffer); remaining = buffer.remaining(); } @@ -708,9 +715,9 @@ class ChannelInputStream extends InputStream { private final BlockingQueue buffers = new LinkedBlockingQueue(BUFFER_LIMIT); - private volatile byte[] currentBuffer; + private final AtomicInteger currentOffset = new AtomicInteger(); - private volatile int currentOffset; + private volatile byte @Nullable [] currentBuffer; private final AtomicInteger available = new AtomicInteger(); @@ -755,20 +762,22 @@ public int read() throws IOException { } return -1; } - if (this.currentBuffer == null) { - this.currentBuffer = getNextBuffer(); - this.currentOffset = 0; - if (this.currentBuffer == null) { + byte[] currentBufferToUse = this.currentBuffer; + if (currentBufferToUse == null) { + currentBufferToUse = getNextBuffer(); + this.currentOffset.set(0); + if (currentBufferToUse == null) { if (TcpNioConnection.this.timedOut) { throw new SocketTimeoutException("Connection has timed out"); } return -1; } + this.currentBuffer = currentBufferToUse; } int bite; - bite = this.currentBuffer[this.currentOffset++] & 0xff; // NOSONAR + bite = currentBufferToUse[this.currentOffset.getAndIncrement()] & 0xff; // NOSONAR this.available.decrementAndGet(); - if (this.currentOffset >= this.currentBuffer.length) { + if (this.currentOffset.get() >= currentBufferToUse.length) { this.currentBuffer = null; } return bite; @@ -778,8 +787,7 @@ public int read() throws IOException { } } - @Nullable - private byte[] getNextBuffer() throws IOException { + private byte @Nullable [] getNextBuffer() throws IOException { byte[] buffer = null; while (buffer == null) { try { @@ -807,8 +815,9 @@ public void write(ByteBuffer byteBuffer) throws IOException { byte[] buffer = new byte[bytesToWrite]; byteBuffer.get(buffer); this.available.addAndGet(bytesToWrite); - if (TcpNioConnection.this.writingLatch != null) { - TcpNioConnection.this.writingLatch.countDown(); + CountDownLatch writingLatchToUse = TcpNioConnection.this.writingLatch; + if (writingLatchToUse != null) { + writingLatchToUse.countDown(); } try { if (!this.buffers.offer(buffer, TcpNioConnection.this.pipeTimeout, TimeUnit.MILLISECONDS)) { diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionSupport.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionSupport.java index ecef525497f..c3b52045206 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionSupport.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionSupport.java @@ -18,8 +18,9 @@ import java.nio.channels.SocketChannel; +import org.jspecify.annotations.Nullable; + import org.springframework.context.ApplicationEventPublisher; -import org.springframework.lang.Nullable; /** * Used by NIO connection factories to instantiate a {@link TcpNioConnection} object. @@ -48,6 +49,6 @@ public interface TcpNioConnectionSupport { TcpNioConnection createNewConnection(SocketChannel socketChannel, boolean server, boolean lookupHost, @Nullable ApplicationEventPublisher applicationEventPublisher, - String connectionFactoryName); + @Nullable String connectionFactoryName); } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioSSLConnection.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioSSLConnection.java index dc8d885c34f..7996431a2de 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioSSLConnection.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioSSLConnection.java @@ -31,8 +31,9 @@ import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLSession; +import org.jspecify.annotations.Nullable; + import org.springframework.context.ApplicationEventPublisher; -import org.springframework.lang.Nullable; import org.springframework.messaging.MessagingException; import org.springframework.util.Assert; @@ -64,8 +65,10 @@ public class TcpNioSSLConnection extends TcpNioConnection { private final SSLEngine sslEngine; + @SuppressWarnings("NullAway.Init") private ByteBuffer decoded; + @SuppressWarnings("NullAway.Init") private ByteBuffer encoded; private final Semaphore semaphore = new Semaphore(0); @@ -76,9 +79,9 @@ public class TcpNioSSLConnection extends TcpNioConnection { private boolean needMoreNetworkData; - private SSLHandshakeException sslFatal; + private @Nullable SSLHandshakeException sslFatal; - private volatile SSLChannelOutputStream sslChannelOutputStream; + private volatile @Nullable SSLChannelOutputStream sslChannelOutputStream; private volatile boolean writerActive; @@ -134,7 +137,7 @@ protected void sendToPipe(final ByteBuffer networkBuffer) throws IOException { } } this.needMoreNetworkData = false; - if (Status.BUFFER_UNDERFLOW == result.getStatus()) { + if (result != null && Status.BUFFER_UNDERFLOW == result.getStatus()) { networkBuffer.compact(); } else { @@ -265,11 +268,9 @@ private HandshakeStatus runTasksIfNeeded(SSLEngineResult result) { * Initializes the SSLEngine and sets up the encryption/decryption buffers. */ public void init() { - if (this.decoded == null) { - this.decoded = allocateEncryptionBuffer(2048); // NOSONAR magic number - this.encoded = allocateEncryptionBuffer(2048); // NOSONAR magic number - initializeEngine(); - } + this.decoded = allocateEncryptionBuffer(2048); + this.encoded = allocateEncryptionBuffer(2048); + initializeEngine(); } private ByteBuffer allocateEncryptionBuffer(int size) { @@ -290,10 +291,12 @@ private void initializeEngine() { protected ChannelOutputStream getChannelOutputStream() { this.monitorLock.lock(); try { - if (this.sslChannelOutputStream == null) { - this.sslChannelOutputStream = new SSLChannelOutputStream(super.getChannelOutputStream()); + SSLChannelOutputStream sslChannelOutputStreamToUse = this.sslChannelOutputStream; + if (sslChannelOutputStreamToUse == null) { + sslChannelOutputStreamToUse = new SSLChannelOutputStream(super.getChannelOutputStream()); + this.sslChannelOutputStream = sslChannelOutputStreamToUse; } - return this.sslChannelOutputStream; + return sslChannelOutputStreamToUse; } finally { this.monitorLock.unlock(); @@ -301,13 +304,16 @@ protected ChannelOutputStream getChannelOutputStream() { } protected SSLChannelOutputStream getSSLChannelOutputStream() { - return this.sslChannelOutputStream != null - ? this.sslChannelOutputStream + SSLChannelOutputStream sslChannelOutputStreamToReturn = this.sslChannelOutputStream; + return sslChannelOutputStreamToReturn != null + ? sslChannelOutputStreamToReturn : (SSLChannelOutputStream) getChannelOutputStream(); } - private String resultToString(SSLEngineResult result) { - return result.toString().replace('\n', ' '); + private String resultToString(@Nullable SSLEngineResult result) { + return result != null + ? result.toString().replace('\n', ' ') + : "null"; } @Override @@ -323,7 +329,7 @@ public void close() { * send to encrypted data to the SocketChannel. * */ - final class SSLChannelOutputStream extends ChannelOutputStream { + protected final class SSLChannelOutputStream extends ChannelOutputStream { private final Lock lock = new ReentrantLock(); diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioServerConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioServerConnectionFactory.java index 91977c9a046..29681b28369 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioServerConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpNioServerConnectionFactory.java @@ -31,7 +31,8 @@ import java.util.HashMap; import java.util.Map; -import org.springframework.lang.Nullable; +import org.jspecify.annotations.Nullable; + import org.springframework.util.Assert; /** @@ -56,9 +57,9 @@ public class TcpNioServerConnectionFactory extends AbstractServerConnectionFacto private boolean usingDirectBuffers; - private volatile ServerSocketChannel serverChannel; + private volatile @Nullable ServerSocketChannel serverChannel; - private volatile Selector selector; + private volatile @Nullable Selector selector; /** * Listens for incoming connections on the port. @@ -69,9 +70,9 @@ public TcpNioServerConnectionFactory(int port) { } /** - * Set to false to only accept one connection per iteration over the + * Set to {@code false} to only accept one connection per iteration over the * selector keys. This might be necessary to avoid accepts overwhelming - * reads of existing sockets. By default when the {@code OP_ACCEPT} operation + * reads of existing sockets. By default, when the {@code OP_ACCEPT} operation * is ready, we will keep accepting connections in a loop until no more arrive. * @param multiAccept false to accept connections one-at-a-time. * @since 5.1.4 @@ -104,11 +105,11 @@ public int getPort() { } @Override - @Nullable - public SocketAddress getServerSocketAddress() { - if (this.serverChannel != null) { + public @Nullable SocketAddress getServerSocketAddress() { + ServerSocketChannel serverChannelToUse = this.serverChannel; + if (serverChannelToUse != null) { try { - return this.serverChannel.getLocalAddress(); + return serverChannelToUse.getLocalAddress(); } catch (IOException ex) { logger.error(ex, "Error getting local address"); @@ -131,29 +132,31 @@ public void run() { return; } try { - this.serverChannel = ServerSocketChannel.open(); + ServerSocketChannel serverChannelToUse = ServerSocketChannel.open(); + this.serverChannel = serverChannelToUse; int port = super.getPort(); - getTcpSocketSupport().postProcessServerSocket(this.serverChannel.socket()); - this.serverChannel.configureBlocking(false); + getTcpSocketSupport().postProcessServerSocket(serverChannelToUse.socket()); + serverChannelToUse.configureBlocking(false); String localAddress = getLocalAddress(); if (localAddress == null) { - this.serverChannel.socket().bind(new InetSocketAddress(port), Math.abs(getBacklog())); + serverChannelToUse.socket().bind(new InetSocketAddress(port), Math.abs(getBacklog())); } else { InetAddress whichNic = InetAddress.getByName(localAddress); - this.serverChannel.socket().bind(new InetSocketAddress(whichNic, port), Math.abs(getBacklog())); + serverChannelToUse.socket().bind(new InetSocketAddress(whichNic, port), Math.abs(getBacklog())); } logger.info(() -> this + " Listening"); - final Selector theSelector = Selector.open(); - if (this.serverChannel == null) { + Selector theSelector = Selector.open(); + serverChannelToUse = this.serverChannel; + if (serverChannelToUse == null) { logger.debug(() -> this + " stopped before registering the server channel"); } else { - this.serverChannel.register(theSelector, SelectionKey.OP_ACCEPT); + serverChannelToUse.register(theSelector, SelectionKey.OP_ACCEPT); setListening(true); publishServerListeningEvent(getPort()); this.selector = theSelector; - doSelect(this.serverChannel, theSelector); + doSelect(serverChannelToUse, theSelector); } } catch (IOException ex) { @@ -292,18 +295,19 @@ private TcpNioConnection createTcpNioConnection(SocketChannel socketChannel) { @Override public void stop() { - setActive(false); - if (this.selector != null) { + Selector selectorToClose = this.selector; + if (selectorToClose != null) { try { - this.selector.close(); + selectorToClose.close(); } catch (Exception ex) { logger.error(ex, "Error closing selector"); } } - if (this.serverChannel != null) { + ServerSocketChannel serverChannelToClose = this.serverChannel; + if (serverChannelToClose != null) { try { - this.serverChannel.close(); + serverChannelToClose.close(); } catch (IOException e) { } @@ -335,7 +339,7 @@ public void setTcpNioConnectionSupport(TcpNioConnectionSupport tcpNioSupport) { /** * @return the serverChannel */ - protected ServerSocketChannel getServerChannel() { + protected @Nullable ServerSocketChannel getServerChannel() { return this.serverChannel; } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpServerConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpServerConnectionFactory.java index c0418551566..11001685429 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpServerConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/TcpServerConnectionFactory.java @@ -18,6 +18,8 @@ import java.net.SocketAddress; +import org.jspecify.annotations.Nullable; + /** * Connection factories that act as TCP servers, listening for incoming connections. * @author Gary Russell @@ -40,6 +42,8 @@ public interface TcpServerConnectionFactory { * is bound to. * @return the socket address. */ - SocketAddress getServerSocketAddress(); + default @Nullable SocketAddress getServerSocketAddress() { + return null; + } } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/ThreadAffinityClientConnectionFactory.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/ThreadAffinityClientConnectionFactory.java index c0a87b86417..97f7a45a496 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/ThreadAffinityClientConnectionFactory.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/ThreadAffinityClientConnectionFactory.java @@ -21,6 +21,8 @@ import javax.net.ssl.SSLSession; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.ApplicationContext; @@ -30,7 +32,6 @@ import org.springframework.core.serializer.Serializer; import org.springframework.expression.Expression; import org.springframework.integration.support.MessageBuilderFactory; -import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.core.DestinationResolver; @@ -52,7 +53,7 @@ public class ThreadAffinityClientConnectionFactory extends AbstractClientConnect /* * Not static because we might have several factories with different delegates. */ - private final ThreadLocal connections = new ThreadLocal<>(); + private final ThreadLocal<@Nullable TcpThreadConnection> connections = new ThreadLocal<>(); public ThreadAffinityClientConnectionFactory(AbstractClientConnectionFactory connectionFactory) { super("", 0); @@ -90,7 +91,7 @@ public void enableManualListenerRegistration() { } @Override - public String getComponentName() { + public @Nullable String getComponentName() { return this.connectionFactory.getComponentName(); } @@ -105,7 +106,7 @@ public void setApplicationEventPublisher(ApplicationEventPublisher applicationEv } @Override - public String getComponentType() { + public @Nullable String getComponentType() { return this.connectionFactory.getComponentType(); } @@ -121,7 +122,6 @@ public void setApplicationContext(ApplicationContext applicationContext) throws } @Override - @Nullable public ApplicationEventPublisher getApplicationEventPublisher() { return this.connectionFactory.getApplicationEventPublisher(); } @@ -132,7 +132,7 @@ public void setChannelResolver(DestinationResolver channelResolv } @Override - public Expression getExpression() { + public @Nullable Expression getExpression() { return this.connectionFactory.getExpression(); } @@ -222,7 +222,7 @@ public void setHost(String host) { } @Override - public String getHost() { + public @Nullable String getHost() { return this.connectionFactory.getHost(); } @@ -232,7 +232,7 @@ public void setPort(int port) { } @Override - public String getApplicationContextId() { + public @Nullable String getApplicationContextId() { return this.connectionFactory.getApplicationContextId(); } @@ -242,12 +242,12 @@ public int getPort() { } @Override - public TcpListener getListener() { + public @Nullable TcpListener getListener() { return this.connectionFactory.getListener(); } @Override - public TcpSender getSender() { + public @Nullable TcpSender getSender() { return this.connectionFactory.getSender(); } @@ -398,7 +398,7 @@ public int hashCode() { } @Override - public Object getPayload() { + public @Nullable Object getPayload() { return this.connection.getPayload(); } @@ -408,12 +408,12 @@ public int getPort() { } @Override - public Object getDeserializerStateKey() { + public @Nullable Object getDeserializerStateKey() { return this.connection.getDeserializerStateKey(); } @Override - public SSLSession getSslSession() { + public @Nullable SSLSession getSslSession() { return this.connection.getSslSession(); } @@ -458,7 +458,7 @@ public void setSerializer(Serializer serializer) { } @Override - public void registerListener(TcpListener listener) { + public void registerListener(@Nullable TcpListener listener) { this.connection.registerListener(listener); } @@ -468,17 +468,17 @@ public void enableManualListenerRegistration() { } @Override - public void registerSender(TcpSender sender) { + public void registerSender(@Nullable TcpSender sender) { this.connection.registerSender(sender); } @Override - public TcpListener getListener() { + public @Nullable TcpListener getListener() { return this.connection.getListener(); } @Override - public TcpSender getSender() { + public @Nullable TcpSender getSender() { return this.connection.getSender(); } @@ -513,7 +513,7 @@ public String toString() { } @Override - public SocketInfo getSocketInfo() { + public @Nullable SocketInfo getSocketInfo() { return this.connection.getSocketInfo(); } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/package-info.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/package-info.java index e25751d69a3..80f8711a8b2 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/package-info.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/connection/package-info.java @@ -2,6 +2,6 @@ * All things related to tcp connections - client and * server factories; listener and sender interfaces. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.integration.ip.tcp.connection; diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/package-info.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/package-info.java index 59dc5d61272..1f44bd65dfb 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/package-info.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/package-info.java @@ -1,4 +1,5 @@ /** * Base package for TCP Support. */ +@org.jspecify.annotations.NullMarked package org.springframework.integration.ip.tcp; diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/AbstractByteArraySerializer.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/AbstractByteArraySerializer.java index 44ce4dca9d6..f4c8f44acef 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/AbstractByteArraySerializer.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/AbstractByteArraySerializer.java @@ -18,6 +18,8 @@ import java.io.IOException; +import org.jspecify.annotations.Nullable; + import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.core.log.LogAccessor; @@ -49,7 +51,7 @@ public abstract class AbstractByteArraySerializer implements private int maxMessageSize = DEFAULT_MAX_MESSAGE_SIZE; - private ApplicationEventPublisher applicationEventPublisher; + private @Nullable ApplicationEventPublisher applicationEventPublisher; /** * The maximum supported message size for this serializer. @@ -76,7 +78,6 @@ public void setApplicationEventPublisher(ApplicationEventPublisher applicationEv protected void checkClosure(int bite) throws IOException { if (bite < 0) { - this.logger.debug("Socket closed during message assembly"); throw new IOException("Socket closed during message assembly"); } } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/AbstractPooledBufferByteArraySerializer.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/AbstractPooledBufferByteArraySerializer.java index 5a5697283ee..d8155c17ead 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/AbstractPooledBufferByteArraySerializer.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/AbstractPooledBufferByteArraySerializer.java @@ -19,6 +19,8 @@ import java.io.IOException; import java.io.InputStream; +import org.jspecify.annotations.Nullable; + import org.springframework.integration.util.SimplePool; import org.springframework.integration.util.SimplePool.PoolItemCallback; import org.springframework.util.Assert; @@ -29,12 +31,13 @@ * * @author Gary Russell * @author Ngoc Nhan + * * @since 4.3 * */ public abstract class AbstractPooledBufferByteArraySerializer extends AbstractByteArraySerializer { - private SimplePool pool; + private @Nullable SimplePool pool; private long poolWaitTimeout = Long.MAX_VALUE; diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/ByteArrayLengthHeaderSerializer.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/ByteArrayLengthHeaderSerializer.java index 674b6de751a..d3d2781c056 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/ByteArrayLengthHeaderSerializer.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/ByteArrayLengthHeaderSerializer.java @@ -138,7 +138,7 @@ public ByteArrayLengthHeaderSerializer inclusive() { public byte[] deserialize(InputStream inputStream) throws IOException { int messageLength = this.readHeader(inputStream) - this.headerAdjust; this.logger.debug(() -> "Message length is " + messageLength); - byte[] messagePart = null; + byte[] messagePart = {}; try { int maxMessageSize = getMaxMessageSize(); if (messageLength > maxMessageSize) { diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/ByteArrayRawSerializer.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/ByteArrayRawSerializer.java index a1ec6a22287..aef024a2435 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/ByteArrayRawSerializer.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/ByteArrayRawSerializer.java @@ -102,12 +102,11 @@ protected byte[] doDeserialize(InputStream inputStream, byte[] buffer) throws IO } return copyToSizedArray(buffer, n); } - catch (SoftEndOfStreamException e) { // NOSONAR catch and throw - throw e; // it's an IO exception and we don't want an event for this - } - catch (IOException | RuntimeException e) { - publishEvent(e, buffer, n); - throw e; + catch (IOException | RuntimeException ex) { + if (!(ex instanceof SoftEndOfStreamException)) { + publishEvent(ex, buffer, n); + } + throw ex; } } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/ByteArraySingleTerminatorSerializer.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/ByteArraySingleTerminatorSerializer.java index d3e1aaabc8a..25f9dc46b55 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/ByteArraySingleTerminatorSerializer.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/ByteArraySingleTerminatorSerializer.java @@ -70,11 +70,10 @@ protected byte[] doDeserialize(InputStream inputStream, byte[] buffer) throws IO } return copyToSizedArray(buffer, n); } - catch (SoftEndOfStreamException e) { // NOSONAR catch and throw - throw e; // it's an IO exception and we don't want an event for this - } catch (IOException | RuntimeException ex) { - publishEvent(ex, buffer, n); + if (!(ex instanceof SoftEndOfStreamException)) { + publishEvent(ex, buffer, n); + } throw ex; } } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/TcpCodecs.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/TcpCodecs.java index c40d282a696..9d683750dda 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/TcpCodecs.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/TcpCodecs.java @@ -29,17 +29,21 @@ * * * @author Gary Russell + * @author Artem Bilan * * @since 5.0 * */ public final class TcpCodecs { - private static ByteArrayLengthHeaderSerializer oneByteLHS; + private static final ByteArrayLengthHeaderSerializer ONE_BYTE_LHS = + new ByteArrayLengthHeaderSerializer(ByteArrayLengthHeaderSerializer.HEADER_SIZE_UNSIGNED_BYTE); - private static ByteArrayLengthHeaderSerializer twoByteLHS; + private static final ByteArrayLengthHeaderSerializer TWO_BYTE_LHS = + new ByteArrayLengthHeaderSerializer(ByteArrayLengthHeaderSerializer.HEADER_SIZE_UNSIGNED_SHORT); - private static ByteArrayLengthHeaderSerializer fourByteLHS; + private static final ByteArrayLengthHeaderSerializer FOUR_BYTE_LHS = + new ByteArrayLengthHeaderSerializer(ByteArrayLengthHeaderSerializer.HEADER_SIZE_INT); private TcpCodecs() { } @@ -98,10 +102,7 @@ public static ByteArraySingleTerminatorSerializer singleTerminator(byte terminat * @see AbstractByteArraySerializer#DEFAULT_MAX_MESSAGE_SIZE */ public static ByteArrayLengthHeaderSerializer lengthHeader1() { - if (oneByteLHS == null) { - oneByteLHS = new ByteArrayLengthHeaderSerializer(ByteArrayLengthHeaderSerializer.HEADER_SIZE_UNSIGNED_BYTE); - } - return oneByteLHS; + return ONE_BYTE_LHS; } /** @@ -110,11 +111,7 @@ public static ByteArrayLengthHeaderSerializer lengthHeader1() { * @see AbstractByteArraySerializer#DEFAULT_MAX_MESSAGE_SIZE */ public static ByteArrayLengthHeaderSerializer lengthHeader2() { - if (twoByteLHS == null) { - twoByteLHS = new ByteArrayLengthHeaderSerializer( - ByteArrayLengthHeaderSerializer.HEADER_SIZE_UNSIGNED_SHORT); - } - return twoByteLHS; + return TWO_BYTE_LHS; } /** @@ -123,10 +120,7 @@ public static ByteArrayLengthHeaderSerializer lengthHeader2() { * @see AbstractByteArraySerializer#DEFAULT_MAX_MESSAGE_SIZE */ public static ByteArrayLengthHeaderSerializer lengthHeader4() { - if (fourByteLHS == null) { - fourByteLHS = new ByteArrayLengthHeaderSerializer(ByteArrayLengthHeaderSerializer.HEADER_SIZE_INT); - } - return fourByteLHS; + return FOUR_BYTE_LHS; } /** diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/package-info.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/package-info.java index 7446699fda6..fcbc92e92e0 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/package-info.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/tcp/serializer/package-info.java @@ -2,5 +2,6 @@ * Byte array (de)serializers for putting some protocol on the * wire so that incoming messages can be constructed from stream data. */ +@org.jspecify.annotations.NullMarked package org.springframework.integration.ip.tcp.serializer; diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/DatagramPacketMessageMapper.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/DatagramPacketMessageMapper.java index 11953ccff9e..f670a9d81c9 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/DatagramPacketMessageMapper.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/DatagramPacketMessageMapper.java @@ -26,6 +26,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.jspecify.annotations.Nullable; + import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; @@ -37,7 +39,6 @@ import org.springframework.integration.support.DefaultMessageBuilderFactory; import org.springframework.integration.support.MessageBuilderFactory; import org.springframework.integration.support.utils.IntegrationUtils; -import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.MessagingException; @@ -81,7 +82,7 @@ public class DatagramPacketMessageMapper implements InboundMessageMapper toMessage(DatagramPacket object) { + public @Nullable Message toMessage(DatagramPacket object) { return toMessage(object, null); } @Override - @Nullable - public Message toMessage(DatagramPacket packet, @Nullable Map headers) { + public @Nullable Message toMessage(DatagramPacket packet, @Nullable Map headers) { int offset = packet.getOffset(); int length = packet.getLength(); byte[] payload; diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/MulticastSendingMessageHandler.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/MulticastSendingMessageHandler.java index dd1d020f348..f44fd285347 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/MulticastSendingMessageHandler.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/MulticastSendingMessageHandler.java @@ -22,10 +22,10 @@ import java.net.InetSocketAddress; import java.net.MulticastSocket; import java.net.NetworkInterface; -import java.net.URISyntaxException; + +import org.jspecify.annotations.Nullable; import org.springframework.expression.Expression; -import org.springframework.messaging.Message; /** * A {@link org.springframework.messaging.MessageHandler} implementation that maps a @@ -45,9 +45,9 @@ public class MulticastSendingMessageHandler extends UnicastSendingMessageHandler private int timeToLive = -1; - private String localAddress; + private @Nullable String localAddress; - private volatile MulticastSocket multicastSocket; + private volatile @Nullable MulticastSocket multicastSocket; /** * Constructs a MulticastSendingMessageHandler to send data to the multicast address/port. @@ -75,7 +75,7 @@ public MulticastSendingMessageHandler(String address, int port, boolean lengthCh * and enables setting the acknowledge option, where the destination sends a receipt acknowledgment. * @param address The multicast address. * @param port The port. - * @param acknowledge Whether or not acknowledgments are required. + * @param acknowledge Whether acknowledgments are required. * @param ackHost The host to which acknowledgments should be sent; required if acknowledge is true. * @param ackPort The port to which acknowledgments should be sent; required if acknowledge is true. * @param ackTimeout How long to wait (milliseconds) for an acknowledgment. @@ -92,7 +92,7 @@ public MulticastSendingMessageHandler(String address, int port, * @param address The multicast address. * @param port The port. * @param lengthCheck Enable the lengthCheck option. - * @param acknowledge Whether or not acknowledgments are required. + * @param acknowledge Whether acknowledgments are required. * @param ackHost The host to which acknowledgments should be sent; required if acknowledge is true. * @param ackPort The port to which acknowledgments should be sent; required if acknowledge is true. * @param ackTimeout How long to wait (milliseconds) for an acknowledgment. @@ -198,12 +198,4 @@ public void setLocalAddress(String localAddress) { this.localAddress = localAddress; } - @Override - protected void convertAndSend(Message message) throws IOException, URISyntaxException { - super.convertAndSend(message); - if (logger.isDebugEnabled()) { - logger.debug("Sent packet to " + this.multicastSocket.getNetworkInterface()); - } - } - } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UdpServerListeningEvent.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UdpServerListeningEvent.java index f55473f3909..71f9d11dca9 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UdpServerListeningEvent.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UdpServerListeningEvent.java @@ -21,10 +21,11 @@ /** * {@link IpIntegrationEvent} emitted when a server begins listening. Useful * when the configured port is zero and the operating system chooses the port. - * Also useful to avoid polling the {@code isListening()} if you need to wait + * Also, useful to avoid polling the {@code isListening()} if you need to wait * before starting some other process to connect to the socket. * * @author Gary Russell + * * @since 5.0.2 */ @SuppressWarnings("serial") diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UnicastReceivingChannelAdapter.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UnicastReceivingChannelAdapter.java index 6ff82c9118d..de3f9afb9df 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UnicastReceivingChannelAdapter.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UnicastReceivingChannelAdapter.java @@ -23,6 +23,7 @@ import java.net.InetSocketAddress; import java.net.SocketException; import java.net.SocketTimeoutException; +import java.util.Objects; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.locks.Lock; @@ -30,10 +31,10 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.springframework.context.ApplicationEventPublisher; +import org.jspecify.annotations.Nullable; + import org.springframework.integration.ip.AbstractInternetProtocolReceivingChannelAdapter; import org.springframework.integration.ip.IpHeaders; -import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.MessagingException; @@ -58,7 +59,7 @@ public class UnicastReceivingChannelAdapter extends AbstractInternetProtocolRece protected final Lock lock = new ReentrantLock(); - private DatagramSocket socket; + private @Nullable DatagramSocket socket; private boolean socketExplicitlySet; @@ -132,10 +133,7 @@ protected void onInit() { public void run() { getSocket(); - ApplicationEventPublisher publisher = getApplicationEventPublisher(); - if (publisher != null) { - publisher.publishEvent(new UdpServerListeningEvent(this, getPort())); - } + getApplicationEventPublisher().publishEvent(new UdpServerListeningEvent(this, getPort())); logger.debug(() -> "UDP Receiver running on port: " + getPort()); @@ -171,7 +169,7 @@ protected void sendAck(Message message) { return; } byte[] ack = id.toString().getBytes(); - String ackAddress = (headers.get(IpHeaders.ACK_ADDRESS, String.class)).trim(); // NOSONAR caller checks header + String ackAddress = Objects.requireNonNull(headers.get(IpHeaders.ACK_ADDRESS, String.class)).trim(); Matcher mat = ADDRESS_PATTERN.matcher(ackAddress); if (!mat.matches()) { throw new MessagingException(message, @@ -305,7 +303,9 @@ protected void doStop() { if (!this.socketExplicitlySet) { this.socket = null; } - datagramSocket.close(); + if (datagramSocket != null) { + datagramSocket.close(); + } } catch (Exception e) { // ignore diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UnicastSendingMessageHandler.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UnicastSendingMessageHandler.java index 3f2d57ce622..789b27d8c0f 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UnicastSendingMessageHandler.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/UnicastSendingMessageHandler.java @@ -37,12 +37,14 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import org.jspecify.annotations.Nullable; + +import org.springframework.beans.factory.BeanFactory; import org.springframework.expression.EvaluationContext; import org.springframework.expression.Expression; import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.integration.ip.AbstractInternetProtocolSendingMessageHandler; import org.springframework.integration.support.utils.IntegrationUtils; -import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.MessagingException; import org.springframework.scheduling.concurrent.CustomizableThreadFactory; @@ -76,7 +78,7 @@ public class UnicastSendingMessageHandler extends private final Map ackControl = Collections.synchronizedMap(new HashMap<>()); - private final Expression destinationExpression; + private final @Nullable Expression destinationExpression; /** * If true adds headers to instruct receiving adapter to return an ack. @@ -85,7 +87,7 @@ public class UnicastSendingMessageHandler extends private boolean acknowledge = false; - private String ackHost; + private @Nullable String ackHost; private int ackPort; @@ -95,22 +97,23 @@ public class UnicastSendingMessageHandler extends private int soReceiveBufferSize = -1; - private String localAddress; + private @Nullable String localAddress; - private DatagramSocket socket; + private @Nullable DatagramSocket socket; - private Executor taskExecutor; + private @Nullable Executor taskExecutor; private boolean taskExecutorSet; - private Expression socketExpression; + private @Nullable Expression socketExpression; + @SuppressWarnings("NullAway.Init") private EvaluationContext evaluationContext; private SocketCustomizer socketCustomizer = (aSocket) -> { }; - private volatile CountDownLatch ackLatch; + private volatile @Nullable CountDownLatch ackLatch; private volatile boolean ackThreadRunning; @@ -157,7 +160,7 @@ public UnicastSendingMessageHandler(Expression destinationExpression) { } /** - * Can used to add a length to each packet which can be checked at the destination. + * Can be used to add a length to each packet which can be checked at the destination. * @param host Destination Host. * @param port Destination Port. * @param lengthCheck If true, packets will contain a length. @@ -269,8 +272,9 @@ public void doStart() { @Override protected void doStop() { closeSocketIfNeeded(); - if (!this.taskExecutorSet && this.taskExecutor != null) { - ((ExecutorService) this.taskExecutor).shutdown(); + Executor taskExecutorToShutdown = this.taskExecutor; + if (!this.taskExecutorSet && taskExecutorToShutdown != null) { + ((ExecutorService) taskExecutorToShutdown).shutdown(); this.taskExecutor = null; } } @@ -278,7 +282,7 @@ protected void doStop() { @Override public void handleMessageInternal(Message message) { if (this.acknowledge) { - Assert.state(this.isRunning(), "When 'acknowledge' is enabled, adapter must be running"); + Assert.state(isRunning(), "When 'acknowledge' is enabled, adapter must be running"); startAckThread(); } CountDownLatch countdownLatch = null; @@ -294,7 +298,7 @@ public void handleMessageInternal(Message message) { this.ackControl.put(messageId, countdownLatch); } convertAndSend(message); - if (waitAck) { + if (countdownLatch != null) { try { if (!countdownLatch.await(this.ackTimeout, TimeUnit.MILLISECONDS)) { throw new MessagingException(message, "Failed to receive UDP Ack in " @@ -320,6 +324,7 @@ public void handleMessageInternal(Message message) { } } + @SuppressWarnings("NullAway") // The logic might be changed to scoped variable eventually public void startAckThread() { if (!this.ackThreadRunning) { this.lock.lock(); @@ -351,6 +356,7 @@ protected void convertAndSend(Message message) throws IOException, URISyntaxE DatagramSocket datagramSocket; if (this.socketExpression != null) { datagramSocket = this.socketExpression.getValue(this.evaluationContext, message, DatagramSocket.class); + Assert.state(datagramSocket != null, () -> "The 'socketExpression' evaluated to null for: " + message); } else { datagramSocket = getSocket(); @@ -376,22 +382,16 @@ protected void convertAndSend(Message message) throws IOException, URISyntaxE destinationAddress = getDestinationAddress(); } DatagramPacket packet = this.mapper.fromMessage(message); - if (packet != null) { - packet.setSocketAddress(destinationAddress); - datagramSocket.send(packet); - logger.debug(() -> "Sent packet for message " + message + " to " + packet.getSocketAddress()); - } - else { - logger.debug(() -> "Mapper created no packet for message " + message); - } + packet.setSocketAddress(destinationAddress); + datagramSocket.send(packet); + logger.debug(() -> "Sent packet for message " + message + " to " + packet.getSocketAddress()); } protected void setSocket(DatagramSocket socket) { this.socket = socket; } - @Nullable - protected DatagramSocket getTheSocket() { + protected @Nullable DatagramSocket getTheSocket() { return this.socket; } @@ -484,7 +484,7 @@ public String getComponentType() { } /** - * @return the acknowledge + * @return true if acknowledgement is enabled. */ public boolean isAcknowledge() { return this.acknowledge; @@ -513,8 +513,9 @@ public int getSoReceiveBufferSize() { @Override protected void onInit() { super.onInit(); - this.mapper.setBeanFactory(getBeanFactory()); - this.evaluationContext = IntegrationContextUtils.getEvaluationContext(getBeanFactory()); + BeanFactory beanFactory = getBeanFactory(); + this.mapper.setBeanFactory(beanFactory); + this.evaluationContext = IntegrationContextUtils.getEvaluationContext(beanFactory); if (this.socketExpression != null) { Assert.state(!this.acknowledge, "'acknowledge' must be false when using a socket expression"); } @@ -536,6 +537,7 @@ protected void setSocketAttributes(DatagramSocket socket) throws SocketException * Process acknowledgments, if requested. */ @Override + @SuppressWarnings("NullAway") // The logic might be changed to scoped variable eventually public void run() { try { this.ackThreadRunning = true; @@ -566,6 +568,10 @@ public void run() { * (bind) error occurred, without bouncing the JVM. */ public void restartAckThread() { + Assert.state(this.acknowledge, + "The UnicastSendingMessageHandler has to be in the 'acknowledgment' mode to run ack thread."); + Assert.state(this.taskExecutor != null, + "The UnicastSendingMessageHandler is not running to schedule an ack thread."); this.taskExecutor.execute(this); } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/package-info.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/package-info.java index e114aa1ed62..6be1cdae55a 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/package-info.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/udp/package-info.java @@ -1,5 +1,5 @@ /** * Base package for UDP support. */ -@org.springframework.lang.NonNullApi +@org.jspecify.annotations.NullMarked package org.springframework.integration.ip.udp; diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/util/TestingUtilities.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/util/TestingUtilities.java index 6baee035556..6be6847ccf0 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/util/TestingUtilities.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/util/TestingUtilities.java @@ -16,10 +16,13 @@ package org.springframework.integration.ip.util; +import java.util.function.Supplier; + +import org.jspecify.annotations.Nullable; + import org.springframework.integration.ip.AbstractInternetProtocolReceivingChannelAdapter; import org.springframework.integration.ip.tcp.connection.AbstractConnectionFactory; import org.springframework.integration.ip.tcp.connection.AbstractServerConnectionFactory; -import org.springframework.lang.Nullable; /** * Convenience class providing methods for testing IP components. @@ -27,6 +30,7 @@ * use in user test code, samples etc. * * @author Gary Russell + * @author Artem Bilan * * @since 2.2 * @@ -42,43 +46,29 @@ private TestingUtilities() { * Wait for a server connection factory to actually start listening before * starting a test. Waits for up to 10 seconds by default. * @param serverConnectionFactory The server connection factory. - * @param delayArg How long to wait in milliseconds; default 10000 (10 seconds) if null. + * @param delay How long to wait in milliseconds; default 10000 (10 seconds) if null. * @throws IllegalStateException If the server does not start listening in time. */ - public static void waitListening(AbstractServerConnectionFactory serverConnectionFactory, @Nullable Long delayArg) + public static void waitListening(AbstractServerConnectionFactory serverConnectionFactory, @Nullable Long delay) throws IllegalStateException { - Long delay = delayArg; - if (delay == null) { - delay = 100L; // NOSONAR magic number - } - else { - delay = delay / 100; // NOSONAR magic number - } - int n = 0; - while (!serverConnectionFactory.isListening()) { - try { - Thread.sleep(100); // NOSONAR magic number - } - catch (InterruptedException e1) { - Thread.currentThread().interrupt(); - throw new IllegalStateException(e1); - } - - if (n++ > delay) { - throw new IllegalStateException("Server didn't start listening."); - } - } + waitListeningInternal(serverConnectionFactory::isListening, delay); } /** * Wait for a server connection factory to actually start listening before * starting a test. Waits for up to 10 seconds by default. * @param adapter The server connection factory. - * @param delayArg How long to wait in milliseconds; default 10000 (10 seconds) if null. + * @param delay How long to wait in milliseconds; default 10000 (10 seconds) if null. * @throws IllegalStateException If the server does not start listening in time. */ - public static void waitListening(AbstractInternetProtocolReceivingChannelAdapter adapter, @Nullable Long delayArg) + public static void waitListening(AbstractInternetProtocolReceivingChannelAdapter adapter, @Nullable Long delay) + throws IllegalStateException { + + waitListeningInternal(adapter::isListening, delay); + } + + private static void waitListeningInternal(Supplier isListeningSupplier, @Nullable Long delayArg) throws IllegalStateException { Long delay = delayArg; @@ -89,7 +79,7 @@ public static void waitListening(AbstractInternetProtocolReceivingChannelAdapter delay = delay / 100; // NOSONAR magic number } int n = 0; - while (!adapter.isListening()) { + while (!isListeningSupplier.get()) { try { Thread.sleep(100); // NOSONAR magic number } diff --git a/spring-integration-ip/src/main/java/org/springframework/integration/ip/util/package-info.java b/spring-integration-ip/src/main/java/org/springframework/integration/ip/util/package-info.java index 4bda5966456..f67aafc3c7e 100644 --- a/spring-integration-ip/src/main/java/org/springframework/integration/ip/util/package-info.java +++ b/spring-integration-ip/src/main/java/org/springframework/integration/ip/util/package-info.java @@ -1,4 +1,5 @@ /** * Provides utilities for IP support. */ +@org.jspecify.annotations.NullMarked package org.springframework.integration.ip.util; diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/config/TcpConnectionFactoryFactoryBeanTest.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/config/TcpConnectionFactoryFactoryBeanTests.java similarity index 80% rename from spring-integration-ip/src/test/java/org/springframework/integration/ip/config/TcpConnectionFactoryFactoryBeanTest.java rename to spring-integration-ip/src/test/java/org/springframework/integration/ip/config/TcpConnectionFactoryFactoryBeanTests.java index 17fa5772a71..57d5bb012f6 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/config/TcpConnectionFactoryFactoryBeanTest.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/config/TcpConnectionFactoryFactoryBeanTests.java @@ -18,24 +18,25 @@ import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.BeanFactory; +import org.springframework.integration.test.support.TestApplicationContextAware; import org.springframework.integration.test.util.TestUtils; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; /** * @author Gary Russell * @author Artem Bilan + * * @since 4.1.1 */ -public class TcpConnectionFactoryFactoryBeanTest { +public class TcpConnectionFactoryFactoryBeanTests implements TestApplicationContextAware { @Test public void testNoReadDelay() throws Exception { TcpConnectionFactoryFactoryBean fb = new TcpConnectionFactoryFactoryBean(); fb.setHost("foo"); - fb.setBeanFactory(mock(BeanFactory.class)); + fb.setBeanFactory(TEST_INTEGRATION_CONTEXT); + fb.setApplicationContext(TEST_INTEGRATION_CONTEXT); fb.afterPropertiesSet(); // INT-3578 IllegalArgumentException on 'readDelay' assertThat(TestUtils.getPropertyValue(fb.getObject(), "readDelay")).isEqualTo(100L); @@ -46,7 +47,8 @@ public void testReadDelay() throws Exception { TcpConnectionFactoryFactoryBean fb = new TcpConnectionFactoryFactoryBean(); fb.setHost("foo"); fb.setReadDelay(1000); - fb.setBeanFactory(mock(BeanFactory.class)); + fb.setBeanFactory(TEST_INTEGRATION_CONTEXT); + fb.setApplicationContext(TEST_INTEGRATION_CONTEXT); fb.afterPropertiesSet(); assertThat(TestUtils.getPropertyValue(fb.getObject(), "readDelay")).isEqualTo(1000L); } diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/AbstractTcpChannelAdapterTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/AbstractTcpChannelAdapterTests.java index 1d5f95050e1..624702339d5 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/AbstractTcpChannelAdapterTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/AbstractTcpChannelAdapterTests.java @@ -30,7 +30,7 @@ */ public class AbstractTcpChannelAdapterTests { - private static final ApplicationEventPublisher NOOP_PUBLISHER = event -> { + static final ApplicationEventPublisher NOOP_PUBLISHER = event -> { }; protected HelloWorldInterceptorFactory newInterceptorFactory() { diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/SyslogdTests-context.xml b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/SyslogdTests-context.xml deleted file mode 100644 index d4cf087c853..00000000000 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/SyslogdTests-context.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/SyslogdTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/SyslogdTests.java deleted file mode 100644 index dd67e8057f5..00000000000 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/SyslogdTests.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2002-present 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.integration.ip.tcp; - -import org.springframework.context.support.AbstractApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -/** - * @author Gary Russell - * @since 2.2 - * - */ -public class SyslogdTests { - - private SyslogdTests() { - super(); - } - - public static void main(String[] args) throws Exception { - AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("SyslogdTests-context.xml", SyslogdTests.class); - // System . out . println("Hit enter to terminate"); - System.in.read(); - ctx.close(); - } - -} diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpInboundGatewayTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpInboundGatewayTests.java index 150d7a414c6..f7df38f99c9 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpInboundGatewayTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpInboundGatewayTests.java @@ -73,7 +73,10 @@ public class TcpInboundGatewayTests implements TestApplicationContextAware { @Test public void testNetSingle() throws Exception { AbstractServerConnectionFactory scf = new TcpNetServerConnectionFactory(0); + scf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + scf.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); scf.setSingleUse(true); + scf.afterPropertiesSet(); TcpInboundGateway gateway = new TcpInboundGateway(); gateway.setConnectionFactory(scf); gateway.setBeanFactory(TEST_INTEGRATION_CONTEXT); @@ -104,7 +107,10 @@ public void testNetSingle() throws Exception { @Test public void testNetNotSingle() throws Exception { AbstractServerConnectionFactory scf = new TcpNetServerConnectionFactory(0); + scf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + scf.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); scf.setSingleUse(false); + scf.afterPropertiesSet(); TcpInboundGateway gateway = new TcpInboundGateway(); gateway.setConnectionFactory(scf); scf.start(); @@ -167,6 +173,9 @@ public void testNetClientMode() throws Exception { assertThat(latch1.await(10, TimeUnit.SECONDS)).isTrue(); AbstractClientConnectionFactory ccf = new TcpNetClientConnectionFactory("localhost", port.get()); ccf.setSingleUse(false); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); TcpInboundGateway gateway = new TcpInboundGateway(); gateway.setConnectionFactory(ccf); final QueueChannel channel = new QueueChannel(); @@ -200,7 +209,10 @@ public void testNetClientMode() throws Exception { @Test public void testNioSingle() throws Exception { AbstractServerConnectionFactory scf = new TcpNioServerConnectionFactory(0); + scf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + scf.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); scf.setSingleUse(true); + scf.afterPropertiesSet(); TcpInboundGateway gateway = new TcpInboundGateway(); gateway.setConnectionFactory(scf); scf.start(); @@ -231,7 +243,10 @@ public void testNioSingle() throws Exception { @Test public void testNioNotSingle() throws Exception { AbstractServerConnectionFactory scf = new TcpNioServerConnectionFactory(0); + scf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + scf.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); scf.setSingleUse(false); + scf.afterPropertiesSet(); TcpInboundGateway gateway = new TcpInboundGateway(); gateway.setConnectionFactory(scf); scf.start(); @@ -248,7 +263,7 @@ public void testNioNotSingle() throws Exception { socket.getOutputStream().write("Test2\r\n".getBytes()); handler.handleMessage(channel.receive(10000)); handler.handleMessage(channel.receive(10000)); - Set results = new HashSet(); + Set results = new HashSet<>(); byte[] bytes = new byte[12]; readFully(socket.getInputStream(), bytes); results.add(new String(bytes)); @@ -257,13 +272,15 @@ public void testNioNotSingle() throws Exception { assertThat(results.remove("Echo:Test1\r\n")).isTrue(); assertThat(results.remove("Echo:Test2\r\n")).isTrue(); gateway.stop(); - scf.stop(); } @Test public void testErrorFlow() throws Exception { AbstractServerConnectionFactory scf = new TcpNetServerConnectionFactory(0); + scf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + scf.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); scf.setSingleUse(true); + scf.afterPropertiesSet(); TcpInboundGateway gateway = new TcpInboundGateway(); gateway.setConnectionFactory(scf); SubscribableChannel errorChannel = new DirectChannel(); @@ -291,7 +308,6 @@ public void testErrorFlow() throws Exception { readFully(socket2.getInputStream(), bytes); assertThat(new String(bytes)).isEqualTo(errorMessage + "\r\n"); gateway.stop(); - scf.stop(); } @Test @@ -310,8 +326,11 @@ public void testNioCloseStream() throws InterruptedException, IOException { private void testCloseStream(AbstractServerConnectionFactory scf, Function ccf) throws InterruptedException, IOException { + scf.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + scf.setBeanFactory(TEST_INTEGRATION_CONTEXT); scf.setSingleUse(true); scf.setDeserializer(new ByteArrayRawSerializer()); + scf.afterPropertiesSet(); TcpInboundGateway gateway = new TcpInboundGateway(); gateway.setConnectionFactory(scf); BeanFactory bf = mock(ConfigurableBeanFactory.class); diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpReceivingChannelAdapterTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpReceivingChannelAdapterTests.java index e7ee76418b9..0841b646912 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpReceivingChannelAdapterTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpReceivingChannelAdapterTests.java @@ -76,6 +76,8 @@ public void testNet() throws Exception { ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); scf.setSerializer(serializer); scf.setDeserializer(serializer); + scf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + scf.afterPropertiesSet(); TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter(); adapter.setConnectionFactory(scf); scf.start(); @@ -129,6 +131,8 @@ public void testNetClientMode() throws Exception { ccf.setSerializer(serializer); ccf.setDeserializer(serializer); ccf.setSoTimeout(Integer.MAX_VALUE); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter(); adapter.setConnectionFactory(ccf); adapter.setClientMode(true); @@ -160,7 +164,6 @@ public void testNetClientMode() throws Exception { @Test public void testNio() throws Exception { AbstractServerConnectionFactory scf = getDefaultServerConnectionFactory(); - noopPublisher(scf); ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); scf.setSerializer(serializer); scf.setDeserializer(serializer); @@ -194,6 +197,9 @@ public void testNetShared() throws Exception { ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); scf.setSerializer(serializer); scf.setDeserializer(serializer); + scf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + scf.afterPropertiesSet(); + TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(scf); TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter(); @@ -224,7 +230,6 @@ public void testNetShared() throws Exception { @Test public void testNioShared() throws Exception { AbstractServerConnectionFactory scf = getDefaultServerConnectionFactory(); - noopPublisher(scf); ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); scf.setSerializer(serializer); scf.setDeserializer(serializer); @@ -262,6 +267,8 @@ public void testNetSingleNoOutbound() throws Exception { scf.setSerializer(serializer); scf.setDeserializer(serializer); scf.setSingleUse(true); + scf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + scf.afterPropertiesSet(); TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter(); adapter.setConnectionFactory(scf); scf.start(); @@ -289,7 +296,6 @@ public void testNetSingleNoOutbound() throws Exception { @Test public void testNioSingleNoOutbound() throws Exception { AbstractServerConnectionFactory scf = getDefaultServerConnectionFactory(); - noopPublisher(scf); ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); scf.setSerializer(serializer); scf.setDeserializer(serializer); @@ -331,6 +337,8 @@ public void testNetSingleShared() throws Exception { scf.setSerializer(serializer); scf.setDeserializer(serializer); scf.setSingleUse(true); + scf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + scf.afterPropertiesSet(); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(scf); TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter(); @@ -363,7 +371,6 @@ public void testNetSingleShared() throws Exception { @Test public void testNioSingleShared() throws Exception { AbstractServerConnectionFactory scf = getDefaultServerConnectionFactory(); - noopPublisher(scf); ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); scf.setSerializer(serializer); scf.setDeserializer(serializer); @@ -400,7 +407,6 @@ public void testNioSingleShared() throws Exception { @Test public void testNioSingleSharedMany() throws Exception { AbstractServerConnectionFactory scf = getDefaultServerConnectionFactory(); - noopPublisher(scf); ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); scf.setSerializer(serializer); scf.setDeserializer(serializer); @@ -461,7 +467,6 @@ public void testNetSingleSharedInterceptors() throws Exception { @Test public void testNioInterceptors() throws Exception { AbstractServerConnectionFactory scf = getDefaultServerConnectionFactory(); - noopPublisher(scf); interceptorsGuts(scf); scf.stop(); } @@ -469,7 +474,6 @@ public void testNioInterceptors() throws Exception { @Test public void testNioSingleNoOutboundInterceptors() throws Exception { AbstractServerConnectionFactory scf = getDefaultServerConnectionFactory(); - noopPublisher(scf); singleNoOutboundInterceptorsGuts(scf); scf.stop(); } @@ -477,7 +481,6 @@ public void testNioSingleNoOutboundInterceptors() throws Exception { @Test public void testNioSingleSharedInterceptors() throws Exception { AbstractServerConnectionFactory scf = getDefaultServerConnectionFactory(); - noopPublisher(scf); singleSharedInterceptorsGuts(scf); scf.stop(); } @@ -486,6 +489,9 @@ private void interceptorsGuts(AbstractServerConnectionFactory scf) throws Except scf.setSerializer(new DefaultSerializer()); scf.setDeserializer(new DefaultDeserializer()); scf.setSingleUse(false); + scf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + scf.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + scf.afterPropertiesSet(); TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter(); adapter.setConnectionFactory(scf); TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain(); @@ -530,6 +536,8 @@ private void singleNoOutboundInterceptorsGuts(AbstractServerConnectionFactory sc newInterceptorFactory() }); scf.setInterceptorFactoryChain(fc); + scf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + scf.afterPropertiesSet(); TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter(); adapter.setConnectionFactory(scf); scf.start(); @@ -574,6 +582,9 @@ private void singleSharedInterceptorsGuts(AbstractServerConnectionFactory scf) t newInterceptorFactory() }); scf.setInterceptorFactoryChain(fc); + scf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + scf.afterPropertiesSet(); + TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(scf); TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter(); @@ -617,7 +628,8 @@ public void testException() throws Exception { ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); scf.setSerializer(serializer); scf.setDeserializer(serializer); - scf.setTaskScheduler(mock(TaskScheduler.class)); + scf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + scf.afterPropertiesSet(); TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter(); adapter.setConnectionFactory(scf); @@ -647,7 +659,9 @@ public void testException() throws Exception { private static AbstractServerConnectionFactory getDefaultServerConnectionFactory() { AbstractServerConnectionFactory scf = new TcpNioServerConnectionFactory(0); - scf.setTaskScheduler(new SimpleAsyncTaskScheduler()); + scf.setApplicationEventPublisher(NOOP_PUBLISHER); + scf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + scf.afterPropertiesSet(); return scf; } diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpSendingMessageHandlerTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpSendingMessageHandlerTests.java index 540fb191a84..dd7dc19f451 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpSendingMessageHandlerTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpSendingMessageHandlerTests.java @@ -68,6 +68,7 @@ import org.springframework.integration.ip.tcp.serializer.ByteArrayStxEtxSerializer; import org.springframework.integration.ip.util.TestingUtilities; import org.springframework.integration.support.MessageBuilder; +import org.springframework.integration.test.support.TestApplicationContextAware; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessagingException; @@ -77,6 +78,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.fail; import static org.awaitility.Awaitility.await; import static org.mockito.Mockito.mock; @@ -88,7 +90,8 @@ * * @since 2.0 */ -public class TcpSendingMessageHandlerTests extends AbstractTcpChannelAdapterTests { +public class TcpSendingMessageHandlerTests extends AbstractTcpChannelAdapterTests + implements TestApplicationContextAware { private static final Log logger = LogFactory.getLog(TcpSendingMessageHandlerTests.class); @@ -102,7 +105,7 @@ private void readFully(InputStream is, byte[] buff) throws IOException { @Test public void testNetCrLf() throws Exception { - final AtomicReference serverSocket = new AtomicReference(); + final AtomicReference serverSocket = new AtomicReference<>(); final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean done = new AtomicBoolean(); this.executor.execute(() -> { @@ -133,6 +136,8 @@ public void testNetCrLf() throws Exception { ccf.setSerializer(serializer); ccf.setDeserializer(serializer); ccf.setSoTimeout(10000); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); ccf.start(); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(ccf); @@ -155,7 +160,7 @@ public void testNetCrLf() throws Exception { @Test public void testNetCrLfClientMode() throws Exception { - final AtomicReference serverSocket = new AtomicReference(); + final AtomicReference serverSocket = new AtomicReference<>(); final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean done = new AtomicBoolean(); this.executor.execute(() -> { @@ -186,6 +191,9 @@ public void testNetCrLfClientMode() throws Exception { ccf.setSerializer(serializer); ccf.setDeserializer(serializer); ccf.setSoTimeout(Integer.MAX_VALUE); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); + ccf.start(); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(ccf); TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter(); @@ -253,6 +261,8 @@ public void testNioCrLf() throws Exception { ccf.setSerializer(serializer); ccf.setDeserializer(serializer); ccf.setSoTimeout(10000); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); ccf.start(); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(ccf); @@ -262,7 +272,7 @@ public void testNioCrLf() throws Exception { adapter.setOutputChannel(channel); handler.handleMessage(MessageBuilder.withPayload("Test").build()); handler.handleMessage(MessageBuilder.withPayload("Test").build()); - Set results = new HashSet(); + Set results = new HashSet<>(); Message mOut = channel.receive(10000); assertThat(mOut).isNotNull(); results.add(new String((byte[]) mOut.getPayload())); @@ -278,7 +288,7 @@ public void testNioCrLf() throws Exception { @Test public void testNetStxEtx() throws Exception { - final AtomicReference serverSocket = new AtomicReference(); + final AtomicReference serverSocket = new AtomicReference<>(); final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean done = new AtomicBoolean(); this.executor.execute(() -> { @@ -309,6 +319,8 @@ public void testNetStxEtx() throws Exception { ccf.setSerializer(serializer); ccf.setDeserializer(serializer); ccf.setSoTimeout(10000); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); ccf.start(); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(ccf); @@ -331,7 +343,7 @@ public void testNetStxEtx() throws Exception { @Test public void testNioStxEtx() throws Exception { - final AtomicReference serverSocket = new AtomicReference(); + final AtomicReference serverSocket = new AtomicReference<>(); final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean done = new AtomicBoolean(); this.executor.execute(() -> { @@ -362,6 +374,8 @@ public void testNioStxEtx() throws Exception { ccf.setSerializer(serializer); ccf.setDeserializer(serializer); ccf.setSoTimeout(10000); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); ccf.start(); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(ccf); @@ -371,7 +385,7 @@ public void testNioStxEtx() throws Exception { adapter.setOutputChannel(channel); handler.handleMessage(MessageBuilder.withPayload("Test").build()); handler.handleMessage(MessageBuilder.withPayload("Test").build()); - Set results = new HashSet(); + Set results = new HashSet<>(); Message mOut = channel.receive(10000); assertThat(mOut).isNotNull(); results.add(new String((byte[]) mOut.getPayload())); @@ -421,6 +435,8 @@ public void testNetLength() throws Exception { ccf.setSerializer(serializer); ccf.setDeserializer(serializer); ccf.setSoTimeout(10000); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); ccf.start(); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(ccf); @@ -477,6 +493,8 @@ public void testNioLength() throws Exception { ccf.setSerializer(serializer); ccf.setDeserializer(serializer); ccf.setSoTimeout(10000); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); ccf.start(); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(ccf); @@ -486,7 +504,7 @@ public void testNioLength() throws Exception { adapter.setOutputChannel(channel); handler.handleMessage(MessageBuilder.withPayload("Test").build()); handler.handleMessage(MessageBuilder.withPayload("Test").build()); - Set results = new HashSet(); + Set results = new HashSet<>(); Message mOut = channel.receive(10000); assertThat(mOut).isNotNull(); results.add(new String((byte[]) mOut.getPayload())); @@ -502,7 +520,7 @@ public void testNioLength() throws Exception { @Test public void testNetSerial() throws Exception { - final AtomicReference serverSocket = new AtomicReference(); + final AtomicReference serverSocket = new AtomicReference<>(); final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean done = new AtomicBoolean(); this.executor.execute(() -> { @@ -532,6 +550,8 @@ public void testNetSerial() throws Exception { ccf.setSerializer(new DefaultSerializer()); ccf.setDeserializer(new DefaultDeserializer()); ccf.setSoTimeout(10000); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); ccf.start(); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(ccf); @@ -584,6 +604,8 @@ public void testNioSerial() throws Exception { ccf.setSerializer(new DefaultSerializer()); ccf.setDeserializer(new DefaultDeserializer()); ccf.setSoTimeout(10000); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); ccf.start(); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(ccf); @@ -593,7 +615,7 @@ public void testNioSerial() throws Exception { adapter.setOutputChannel(channel); handler.handleMessage(MessageBuilder.withPayload("Test").build()); handler.handleMessage(MessageBuilder.withPayload("Test").build()); - Set results = new HashSet(); + Set results = new HashSet<>(); Message mOut = channel.receive(10000); assertThat(mOut).isNotNull(); results.add((String) mOut.getPayload()); @@ -609,7 +631,7 @@ public void testNioSerial() throws Exception { @Test public void testNetSingleUseNoInbound() throws Exception { - final AtomicReference serverSocket = new AtomicReference(); + final AtomicReference serverSocket = new AtomicReference<>(); final CountDownLatch latch = new CountDownLatch(1); final Semaphore semaphore = new Semaphore(0); final AtomicBoolean done = new AtomicBoolean(); @@ -642,6 +664,8 @@ public void testNetSingleUseNoInbound() throws Exception { ccf.setSerializer(serializer); ccf.setDeserializer(serializer); ccf.setSoTimeout(10000); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); ccf.start(); ccf.setSingleUse(true); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); @@ -656,7 +680,7 @@ public void testNetSingleUseNoInbound() throws Exception { @Test public void testNioSingleUseNoInbound() throws Exception { - final AtomicReference serverSocket = new AtomicReference(); + final AtomicReference serverSocket = new AtomicReference<>(); final CountDownLatch latch = new CountDownLatch(1); final Semaphore semaphore = new Semaphore(0); final AtomicBoolean done = new AtomicBoolean(); @@ -689,6 +713,8 @@ public void testNioSingleUseNoInbound() throws Exception { ccf.setSerializer(serializer); ccf.setDeserializer(serializer); ccf.setSoTimeout(5000); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); ccf.start(); ccf.setSingleUse(true); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); @@ -703,7 +729,7 @@ public void testNioSingleUseNoInbound() throws Exception { @Test public void testNetSingleUseWithInbound() throws Exception { - final AtomicReference serverSocket = new AtomicReference(); + final AtomicReference serverSocket = new AtomicReference<>(); final CountDownLatch latch = new CountDownLatch(1); final Semaphore semaphore = new Semaphore(0); final AtomicBoolean done = new AtomicBoolean(); @@ -737,6 +763,8 @@ public void testNetSingleUseWithInbound() throws Exception { ccf.setSerializer(serializer); ccf.setDeserializer(serializer); ccf.setSoTimeout(10000); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); ccf.start(); ccf.setSingleUse(true); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); @@ -748,7 +776,7 @@ public void testNetSingleUseWithInbound() throws Exception { handler.handleMessage(MessageBuilder.withPayload("Test").build()); handler.handleMessage(MessageBuilder.withPayload("Test").build()); assertThat(semaphore.tryAcquire(2, 10000, TimeUnit.MILLISECONDS)).isTrue(); - Set replies = new HashSet(); + Set replies = new HashSet<>(); for (int i = 0; i < 2; i++) { Message mOut = channel.receive(10000); assertThat(mOut).isNotNull(); @@ -763,7 +791,7 @@ public void testNetSingleUseWithInbound() throws Exception { @Test public void testNioSingleUseWithInbound() throws Exception { - final AtomicReference serverSocket = new AtomicReference(); + final AtomicReference serverSocket = new AtomicReference<>(); final CountDownLatch latch = new CountDownLatch(1); final Semaphore semaphore = new Semaphore(0); final AtomicBoolean done = new AtomicBoolean(); @@ -797,8 +825,10 @@ public void testNioSingleUseWithInbound() throws Exception { ccf.setSerializer(serializer); ccf.setDeserializer(serializer); ccf.setSoTimeout(10000); - ccf.start(); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); ccf.setSingleUse(true); + ccf.start(); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(ccf); TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter(); @@ -808,7 +838,7 @@ public void testNioSingleUseWithInbound() throws Exception { handler.handleMessage(MessageBuilder.withPayload("Test").build()); handler.handleMessage(MessageBuilder.withPayload("Test").build()); assertThat(semaphore.tryAcquire(2, 10000, TimeUnit.MILLISECONDS)).isTrue(); - Set replies = new HashSet(); + Set replies = new HashSet<>(); for (int i = 0; i < 2; i++) { Message mOut = channel.receive(10000); assertThat(mOut).isNotNull(); @@ -823,11 +853,11 @@ public void testNioSingleUseWithInbound() throws Exception { @Test public void testNioSingleUseWithInboundMany() throws Exception { - final AtomicReference serverSocket = new AtomicReference(); + final AtomicReference serverSocket = new AtomicReference<>(); final CountDownLatch latch = new CountDownLatch(1); final Semaphore semaphore = new Semaphore(0); final AtomicBoolean done = new AtomicBoolean(); - final List serverSockets = new ArrayList(); + final List serverSockets = new ArrayList<>(); this.executor.execute(() -> { try { ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(0, 100); @@ -875,6 +905,8 @@ public void testNioSingleUseWithInboundMany() throws Exception { ccf.setSoTimeout(10000); ccf.setSingleUse(true); ccf.setTaskExecutor(this.executor); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); ccf.start(); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(ccf); @@ -893,7 +925,7 @@ public void testNioSingleUseWithInboundMany() throws Exception { fail("Exception at " + i); } assertThat(semaphore.tryAcquire(100, 20000, TimeUnit.MILLISECONDS)).isTrue(); - Set replies = new HashSet(); + Set replies = new HashSet<>(); for (i = 100; i < 200; i++) { Message mOut = channel.receive(20000); assertThat(mOut).isNotNull(); @@ -909,7 +941,7 @@ public void testNioSingleUseWithInboundMany() throws Exception { @Test public void testNetNegotiate() throws Exception { - final AtomicReference serverSocket = new AtomicReference(); + final AtomicReference serverSocket = new AtomicReference<>(); final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean done = new AtomicBoolean(); this.executor.execute(() -> { @@ -958,6 +990,8 @@ public void testNetNegotiate() throws Exception { newInterceptorFactory() }); ccf.setInterceptorFactoryChain(fc); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); ccf.start(); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(ccf); @@ -980,7 +1014,7 @@ public void testNetNegotiate() throws Exception { @Test public void testNioNegotiate() throws Exception { - final AtomicReference serverSocket = new AtomicReference(); + final AtomicReference serverSocket = new AtomicReference<>(); final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean done = new AtomicBoolean(); this.executor.execute(() -> { @@ -1020,8 +1054,10 @@ public void testNioNegotiate() throws Exception { ccf.setDeserializer(new DefaultDeserializer()); ccf.setSoTimeout(10000); TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain(); - fc.setInterceptors(new TcpConnectionInterceptorFactory[] {newInterceptorFactory()}); + fc.setInterceptor(newInterceptorFactory()); ccf.setInterceptorFactoryChain(fc); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); ccf.start(); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(ccf); @@ -1032,7 +1068,7 @@ public void testNioNegotiate() throws Exception { for (int i = 0; i < 1000; i++) { handler.handleMessage(MessageBuilder.withPayload("Test").build()); } - Set results = new TreeSet(); + Set results = new TreeSet<>(); for (int i = 0; i < 1000; i++) { Message mOut = channel.receive(10000); assertThat(mOut).isNotNull(); @@ -1049,7 +1085,7 @@ public void testNioNegotiate() throws Exception { @Test public void testNetNegotiateSingleNoListen() throws Exception { - final AtomicReference serverSocket = new AtomicReference(); + final AtomicReference serverSocket = new AtomicReference<>(); final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean done = new AtomicBoolean(); this.executor.execute(() -> { @@ -1089,12 +1125,11 @@ public void testNetNegotiateSingleNoListen() throws Exception { ccf.setDeserializer(new DefaultDeserializer()); ccf.setSoTimeout(10000); TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain(); - fc.setInterceptors(new TcpConnectionInterceptorFactory[] { - newInterceptorFactory(), - newInterceptorFactory() - }); + fc.setInterceptor(newInterceptorFactory(), newInterceptorFactory()); ccf.setInterceptorFactoryChain(fc); ccf.setSingleUse(true); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); ccf.start(); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(ccf); @@ -1106,7 +1141,7 @@ public void testNetNegotiateSingleNoListen() throws Exception { @Test public void testNioNegotiateSingleNoListen() throws Exception { - final AtomicReference serverSocket = new AtomicReference(); + final AtomicReference serverSocket = new AtomicReference<>(); final CountDownLatch latch = new CountDownLatch(1); final AtomicBoolean done = new AtomicBoolean(); this.executor.execute(() -> { @@ -1152,6 +1187,8 @@ public void testNioNegotiateSingleNoListen() throws Exception { }); ccf.setInterceptorFactoryChain(fc); ccf.setSingleUse(true); + ccf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + ccf.afterPropertiesSet(); ccf.start(); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(ccf); @@ -1162,18 +1199,18 @@ public void testNioNegotiateSingleNoListen() throws Exception { } @Test - public void testOutboundChannelAdapterWithinChain() throws Exception { + public void testOutboundChannelAdapterWithinChain() { AbstractApplicationContext ctx = new ClassPathXmlApplicationContext( "TcpOutboundChannelAdapterWithinChainTests-context.xml", this.getClass()); AbstractServerConnectionFactory scf = ctx.getBean(AbstractServerConnectionFactory.class); TestingUtilities.waitListening(scf, null); ctx.getBean(AbstractClientConnectionFactory.class).setPort(scf.getPort()); - ctx.getBeansOfType(ConsumerEndpointFactoryBean.class).values().forEach(c -> c.start()); + ctx.getBeansOfType(ConsumerEndpointFactoryBean.class).values().forEach(ConsumerEndpointFactoryBean::start); MessageChannel channelAdapterWithinChain = ctx.getBean("tcpOutboundChannelAdapterWithinChain", MessageChannel.class); PollableChannel inbound = ctx.getBean("inbound", PollableChannel.class); String testPayload = "Hello, world!"; - channelAdapterWithinChain.send(new GenericMessage(testPayload)); + channelAdapterWithinChain.send(new GenericMessage<>(testPayload)); Message m = inbound.receive(1000); assertThat(m).isNotNull(); assertThat(new String((byte[]) m.getPayload())).isEqualTo(testPayload); @@ -1188,16 +1225,11 @@ public void testConnectionException() throws Exception { throw new SocketException("Failed to connect"); }).when(mockCcf).getConnection(); handler.setConnectionFactory(mockCcf); - try { - handler.handleMessage(new GenericMessage("foo")); - fail("Expected exception"); - } - catch (Exception e) { - assertThat(e instanceof MessagingException).isTrue(); - assertThat(e.getCause() != null).isTrue(); - assertThat(e.getCause() instanceof SocketException).isTrue(); - assertThat(e.getCause().getMessage()).isEqualTo("Failed to connect"); - } + + assertThatExceptionOfType(MessagingException.class) + .isThrownBy(() -> handler.handleMessage(new GenericMessage<>("foo"))) + .withCauseInstanceOf(SocketException.class) + .withStackTraceContaining("Failed to connect"); } @Test @@ -1208,6 +1240,8 @@ public void testInterceptedConnection() throws Exception { ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); scf.setSerializer(serializer); scf.setDeserializer(serializer); + scf.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + scf.setBeanFactory(TEST_INTEGRATION_CONTEXT); TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter(); adapter.setConnectionFactory(scf); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); @@ -1223,6 +1257,7 @@ public void testInterceptedConnection() throws Exception { TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain(); fc.setInterceptor(newInterceptorFactory(scf.getApplicationEventPublisher())); scf.setInterceptorFactoryChain(fc); + scf.afterPropertiesSet(); scf.start(); TestingUtilities.waitListening(scf, null); int port = scf.getPort(); @@ -1242,6 +1277,8 @@ public void testInterceptedCleanup() throws Exception { ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer(); scf.setSerializer(serializer); scf.setDeserializer(serializer); + scf.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + scf.setBeanFactory(TEST_INTEGRATION_CONTEXT); TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter(); adapter.setConnectionFactory(scf); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); @@ -1254,6 +1291,7 @@ public void testInterceptedCleanup() throws Exception { TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain(); fc.setInterceptor(newInterceptorFactory(scf.getApplicationEventPublisher())); scf.setInterceptorFactoryChain(fc); + scf.afterPropertiesSet(); scf.start(); TestingUtilities.waitListening(scf, null); int port = scf.getPort(); @@ -1263,4 +1301,5 @@ public void testInterceptedCleanup() throws Exception { await().untilAsserted(() -> assertThat(handler.getConnections()).isEmpty()); scf.stop(); } + } diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpSendingNoSocketTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpSendingNoSocketTests.java index e6696162f50..0b8ff31cd50 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpSendingNoSocketTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/TcpSendingNoSocketTests.java @@ -16,20 +16,24 @@ package org.springframework.integration.ip.tcp; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.integration.ip.tcp.connection.AbstractServerConnectionFactory; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageHandlingException; import org.springframework.messaging.support.GenericMessage; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.BDDMockito.given; /** * @author Gary Russell + * @author Artem Bilan + * * @since 2.2 * */ @@ -43,20 +47,25 @@ public class TcpSendingNoSocketTests { @Autowired private MessageChannel advised; + @Autowired + private AbstractServerConnectionFactory mockCf; + + @BeforeEach + void setup() { + given(mockCf.getApplicationEventPublisher()).willReturn(event -> { + }); + } + @Test public void exceptionExpected() { - try { - shouldFail.send(new GenericMessage("foo")); - fail("Exception expected"); - } - catch (MessageHandlingException e) { - assertThat(e.getMessage()).startsWith("Unable to find outbound socket"); - } + assertThatExceptionOfType(MessageHandlingException.class) + .isThrownBy(() -> shouldFail.send(new GenericMessage<>("foo"))) + .withMessageStartingWith("Unable to find outbound socket"); } @Test public void exceptionTrapped() { - advised.send(new GenericMessage("foo")); + advised.send(new GenericMessage<>("foo")); } } diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactoryTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactoryTests.java index 4d5656cf42d..82a467d468b 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactoryTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/CachingClientConnectionFactoryTests.java @@ -537,6 +537,8 @@ public void testCachedFailoverRealClose() throws Exception { latch1.countDown(); return false; }); + server1.setBeanFactory(TEST_INTEGRATION_CONTEXT); + server1.afterPropertiesSet(); server1.start(); TestingUtilities.waitListening(server1, 10000L); int port1 = server1.getPort(); @@ -547,6 +549,8 @@ public void testCachedFailoverRealClose() throws Exception { latch2.countDown(); return false; }); + server2.setBeanFactory(TEST_INTEGRATION_CONTEXT); + server2.afterPropertiesSet(); server2.start(); TestingUtilities.waitListening(server2, 10000L); int port2 = server2.getPort(); @@ -606,6 +610,9 @@ public void testCachedFailoverRealBadHost() throws Exception { latch1.countDown(); return false; }); + server1.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + server1.setBeanFactory(TEST_INTEGRATION_CONTEXT); + server1.afterPropertiesSet(); server1.start(); TestingUtilities.waitListening(server1, 10000L); int port1 = server1.getPort(); @@ -616,6 +623,9 @@ public void testCachedFailoverRealBadHost() throws Exception { latch2.countDown(); return false; }); + server2.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + server2.setBeanFactory(TEST_INTEGRATION_CONTEXT); + server2.afterPropertiesSet(); server2.start(); TestingUtilities.waitListening(server2, 10000L); int port2 = server2.getPort(); @@ -623,9 +633,15 @@ public void testCachedFailoverRealBadHost() throws Exception { AbstractClientConnectionFactory factory1 = new TcpNetClientConnectionFactory("junkjunk", port1); factory1.setBeanName("client1"); factory1.registerListener(message -> false); + factory1.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + factory1.setBeanFactory(TEST_INTEGRATION_CONTEXT); + factory1.afterPropertiesSet(); AbstractClientConnectionFactory factory2 = new TcpNetClientConnectionFactory("localhost", port2); factory2.setBeanName("client2"); factory2.registerListener(message -> false); + factory2.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + factory2.setBeanFactory(TEST_INTEGRATION_CONTEXT); + factory2.afterPropertiesSet(); List factories = new ArrayList<>(); factories.add(factory1); factories.add(factory2); @@ -668,10 +684,14 @@ public void testRealConnection() throws Exception { latch2.countDown(); return false; }); + in.setBeanFactory(TEST_INTEGRATION_CONTEXT); + in.afterPropertiesSet(); in.start(); TestingUtilities.waitListening(in, null); int port = in.getPort(); TcpNetClientConnectionFactory out = new TcpNetClientConnectionFactory("localhost", port); + out.setBeanFactory(TEST_INTEGRATION_CONTEXT); + out.afterPropertiesSet(); CachingClientConnectionFactory cache = new CachingClientConnectionFactory(out, 1); cache.setSingleUse(false); cache.setConnectionWaitTimeout(100); @@ -702,6 +722,7 @@ public void testGatewayRelease() { TcpNetServerConnectionFactory in = new TcpNetServerConnectionFactory(0); in.setTaskScheduler(new SimpleAsyncTaskScheduler()); in.setApplicationEventPublisher(mock(ApplicationEventPublisher.class)); + in.setBeanFactory(TEST_INTEGRATION_CONTEXT); final TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); handler.setConnectionFactory(in); final AtomicInteger count = new AtomicInteger(2); @@ -719,6 +740,7 @@ public void testGatewayRelease() { } return false; }); + in.afterPropertiesSet(); handler.setBeanFactory(mock(BeanFactory.class)); handler.afterPropertiesSet(); handler.start(); @@ -726,6 +748,8 @@ public void testGatewayRelease() { int port = in.getPort(); TcpNetClientConnectionFactory out = new TcpNetClientConnectionFactory("localhost", port); out.setApplicationEventPublisher(mock(ApplicationEventPublisher.class)); + out.setBeanFactory(TEST_INTEGRATION_CONTEXT); + out.afterPropertiesSet(); CachingClientConnectionFactory cache = new CachingClientConnectionFactory(out, 2); TcpOutboundGateway gate = new TcpOutboundGateway(); gate.setConnectionFactory(cache); @@ -794,6 +818,8 @@ public boolean isActive() { }; factory.setApplicationEventPublisher(mock(ApplicationEventPublisher.class)); + factory.setBeanFactory(TEST_INTEGRATION_CONTEXT); + factory.afterPropertiesSet(); final CachingClientConnectionFactory cachingFactory = new CachingClientConnectionFactory(factory, 1); final AtomicReference> received = new AtomicReference<>(); cachingFactory.registerListener(message -> { diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/ConnectionFactoryShutDownTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/ConnectionFactoryShutDownTests.java index 5fedef19990..92ba17a4579 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/ConnectionFactoryShutDownTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/ConnectionFactoryShutDownTests.java @@ -46,6 +46,7 @@ public TcpConnection getConnection() { } }; + factory.start(); factory.setActive(true); Executor executor = factory.getTaskExecutor(); final CountDownLatch latch1 = new CountDownLatch(1); diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/ConnectionFactoryTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/ConnectionFactoryTests.java index 8a9dffac540..374dd764c34 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/ConnectionFactoryTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/ConnectionFactoryTests.java @@ -61,7 +61,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.fail; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.awaitility.Awaitility.await; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; @@ -83,7 +83,7 @@ public class ConnectionFactoryTests implements TestApplicationContextAware { @Test void netOpenEventOnReadThread() throws InterruptedException, IOException { - TcpNetServerConnectionFactory server = getTcpNetServerConnectionFactory(0); + TcpNetServerConnectionFactory server = new TcpNetServerConnectionFactory(0); AtomicReference readThread = new AtomicReference<>(); AtomicReference openEventThread = new AtomicReference<>(); CountDownLatch latch1 = new CountDownLatch(1); @@ -135,8 +135,7 @@ public void testObtainConnectionIdsNio() throws Exception { } public void testObtainConnectionIds(AbstractServerConnectionFactory serverFactory) throws Exception { - final List events = - Collections.synchronizedList(new ArrayList()); + final List events = Collections.synchronizedList(new ArrayList<>()); int expectedEvents = serverFactory instanceof TcpNetServerConnectionFactory ? 7 // Listening, + OPEN, CLOSE, EXCEPTION for each side : 5; // Listening, + OPEN, CLOSE (but we *might* get exceptions, depending on timing). @@ -152,6 +151,7 @@ public void testObtainConnectionIds(AbstractServerConnectionFactory serverFactor }; serverFactory.setBeanName("serverFactory"); serverFactory.setApplicationEventPublisher(publisher); + serverFactory.setBeanFactory(TEST_INTEGRATION_CONTEXT); serverFactory = spy(serverFactory); final CountDownLatch serverConnectionInitLatch = new CountDownLatch(1); doAnswer(invocation -> { @@ -164,6 +164,7 @@ public void testObtainConnectionIds(AbstractServerConnectionFactory serverFactor scheduler.afterPropertiesSet(); serverFactory.setTaskScheduler(new SimpleAsyncTaskScheduler()); + serverFactory.afterPropertiesSet(); TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter(); adapter.setOutputChannel(new NullChannel()); adapter.setConnectionFactory(serverFactory); @@ -188,7 +189,7 @@ public void testObtainConnectionIds(AbstractServerConnectionFactory serverFactor assertThat(serverFactory.closeConnection(servers.get(0))).isTrue(); servers = serverFactory.getOpenConnectionIds(); assertThat(servers.size()).isEqualTo(0); - await().atMost(Duration.ofSeconds(10)).until(() -> clientFactory.getOpenConnectionIds().size() == 0); + await().atMost(Duration.ofSeconds(10)).until(() -> clientFactory.getOpenConnectionIds().isEmpty()); clients = clientFactory.getOpenConnectionIds(); assertThat(clients.size()).isEqualTo(0); assertThat(eventLatch.await(10, TimeUnit.SECONDS)).isTrue(); @@ -202,18 +203,14 @@ public void testObtainConnectionIds(AbstractServerConnectionFactory serverFactor .as("Expected at least " + expectedEvents + " events; got: " + events.size() + " : " + events) .isGreaterThanOrEqualTo(expectedEvents + 1); - try { - event = new FooEvent(mock(TcpConnectionSupport.class), "foo"); - client.publishEvent(event); - fail("Expected exception"); - } - catch (IllegalArgumentException e) { - assertThat("Can only publish events with this as the source".equals(e.getMessage())).isTrue(); - } + FooEvent wrongEvent = new FooEvent(mock(TcpConnectionSupport.class), "foo"); + + assertThatIllegalArgumentException() + .isThrownBy(() -> client.publishEvent(wrongEvent)) + .withMessage("Can only publish events with this as the source"); SocketAddress address = serverFactory.getServerSocketAddress(); - if (address instanceof InetSocketAddress) { - InetSocketAddress inetAddress = (InetSocketAddress) address; + if (address instanceof InetSocketAddress inetAddress) { assertThat(inetAddress.getPort()).isEqualTo(port); } serverFactory.stop(); @@ -224,16 +221,10 @@ public void testObtainConnectionIds(AbstractServerConnectionFactory serverFactor public void testEarlyCloseNio() throws Exception { AbstractServerConnectionFactory factory = new TcpNioServerConnectionFactory(0); factory.setBeanFactory(TEST_INTEGRATION_CONTEXT); - testEarlyClose(factory, "serverChannel", " stopped before registering the server channel"); - } + factory.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); - private void testEarlyClose(final AbstractServerConnectionFactory factory, String property, - String message) throws Exception { - - factory.setApplicationEventPublisher(mock(ApplicationEventPublisher.class)); factory.setBeanName("foo"); factory.registerListener(mock(TcpListener.class)); - factory.afterPropertiesSet(); LogAccessor logAccessor = TestUtils.getPropertyValue(factory, "logger", LogAccessor.class); Log logger = spy(logAccessor.getLog()); new DirectFieldAccessor(logAccessor).setPropertyValue("log", logger); @@ -251,8 +242,11 @@ private void testEarlyClose(final AbstractServerConnectionFactory factory, Strin doAnswer(invocation -> { latch3.countDown(); return null; - }).when(logger).debug(argThat(logMessage -> logMessage.toString().contains(message))); + }).when(logger).debug(argThat(logMessage -> + logMessage.toString().contains(" stopped before registering the server channel"))); + factory.afterPropertiesSet(); factory.start(); + assertThat(latch1.await(10, TimeUnit.SECONDS)).as("missing info log").isTrue(); // stop on a different thread because it waits for the executor new SimpleAsyncTaskExecutor("testEarlyClose-") @@ -260,10 +254,10 @@ private void testEarlyClose(final AbstractServerConnectionFactory factory, Strin int n = 0; DirectFieldAccessor accessor = new DirectFieldAccessor(factory); await("Stop was not invoked in time").atMost(Duration.ofSeconds(20)) - .until(() -> accessor.getPropertyValue(property) == null); + .until(() -> accessor.getPropertyValue("serverChannel") == null); latch2.countDown(); assertThat(latch3.await(10, TimeUnit.SECONDS)).as("missing debug log").isTrue(); - String expected = "bean 'foo', port=" + factory.getPort() + message; + String expected = "bean 'foo', port=" + factory.getPort() + " stopped before registering the server channel"; ArgumentCaptor captor = ArgumentCaptor.forClass(LogMessage.class); verify(logger, atLeast(1)).debug(captor.capture()); assertThat(captor.getAllValues().stream().map(Object::toString).collect(Collectors.toList())).contains(expected); @@ -272,22 +266,22 @@ private void testEarlyClose(final AbstractServerConnectionFactory factory, Strin @Test void healthCheckSuccessNet() throws InterruptedException { - healthCheckSuccess(getTcpNetServerConnectionFactory(0), false); + healthCheckSuccess(new TcpNetServerConnectionFactory(0), false); } @Test void healthCheckSuccessNio() throws InterruptedException { - healthCheckSuccess(getTcpNetServerConnectionFactory(0), false); + healthCheckSuccess(new TcpNioServerConnectionFactory(0), false); } @Test void healthCheckFailureNet() throws InterruptedException { - healthCheckSuccess(getTcpNetServerConnectionFactory(0), true); + healthCheckSuccess(new TcpNetServerConnectionFactory(0), true); } @Test void healthCheckFailureNio() throws InterruptedException { - healthCheckSuccess(getTcpNetServerConnectionFactory(0), true); + healthCheckSuccess(new TcpNioServerConnectionFactory(0), true); } private void healthCheckSuccess(AbstractServerConnectionFactory server, boolean fail) throws InterruptedException { @@ -299,9 +293,7 @@ private void healthCheckSuccess(AbstractServerConnectionFactory server, boolean }); server.setTaskScheduler(new SimpleAsyncTaskScheduler()); AtomicReference connection = new AtomicReference<>(); - server.registerSender(conn -> { - connection.set(conn); - }); + server.registerSender(connection::set); AtomicInteger tested = new AtomicInteger(); server.registerListener(msg -> { if (!(msg instanceof ErrorMessage)) { @@ -316,7 +308,10 @@ private void healthCheckSuccess(AbstractServerConnectionFactory server, boolean } return false; }); + server.setBeanFactory(TEST_INTEGRATION_CONTEXT); + server.afterPropertiesSet(); server.start(); + assertThat(serverUp.await(10, TimeUnit.SECONDS)).isTrue(); TcpNetClientConnectionFactory clientFactory = new TcpNetClientConnectionFactory("localhost", server.getPort()); clientFactory.setApplicationEventPublisher(event -> { @@ -340,6 +335,9 @@ private void healthCheckSuccess(AbstractServerConnectionFactory server, boolean } return result.get(); }); + clientFactory.setBeanFactory(TEST_INTEGRATION_CONTEXT); + clientFactory.afterPropertiesSet(); + TcpOutboundGateway gateway = new TcpOutboundGateway(); gateway.setRemoteTimeout(60000); gateway.setConnectionFactory(clientFactory); @@ -366,12 +364,6 @@ private void healthCheckSuccess(AbstractServerConnectionFactory server, boolean server.stop(); } - private TcpNetServerConnectionFactory getTcpNetServerConnectionFactory(int port) { - TcpNetServerConnectionFactory result = new TcpNetServerConnectionFactory(port); - result.setTaskScheduler(new SimpleAsyncTaskScheduler()); - return result; - } - @SuppressWarnings("serial") private class FooEvent extends TcpConnectionOpenEvent { diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/FailoverClientConnectionFactoryTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/FailoverClientConnectionFactoryTests.java index be442708877..b3624f1cd17 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/FailoverClientConnectionFactoryTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/FailoverClientConnectionFactoryTests.java @@ -208,6 +208,8 @@ void failoverAllDeadAfterSuccess() throws Exception { latch.countDown(); } }); + cf1.setBeanFactory(TEST_INTEGRATION_CONTEXT); + cf1.afterPropertiesSet(); cf2.setApplicationEventPublisher(event -> { }); FailoverClientConnectionFactory fccf = new FailoverClientConnectionFactory(List.of(cf1, cf2)); @@ -387,21 +389,27 @@ public void testRealNioSingleUse() throws Exception { public void testFailoverCachedRealClose() throws Exception { TcpNetServerConnectionFactory server1 = new TcpNetServerConnectionFactory(0); server1.setBeanName("server1"); + server1.setBeanFactory(TEST_INTEGRATION_CONTEXT); + server1.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); final CountDownLatch latch1 = new CountDownLatch(3); server1.registerListener(message -> { latch1.countDown(); return false; }); + server1.afterPropertiesSet(); server1.start(); TestingUtilities.waitListening(server1, 10000L); int port1 = server1.getPort(); TcpNetServerConnectionFactory server2 = new TcpNetServerConnectionFactory(0); server2.setBeanName("server2"); + server2.setBeanFactory(TEST_INTEGRATION_CONTEXT); + server2.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); final CountDownLatch latch2 = new CountDownLatch(2); server2.registerListener(message -> { latch2.countDown(); return false; }); + server2.afterPropertiesSet(); server2.start(); TestingUtilities.waitListening(server2, 10000L); int port2 = server2.getPort(); @@ -462,6 +470,7 @@ public void testFailoverCachedRealClose() throws Exception { public void testFailoverCachedWithGateway() { final TcpNetServerConnectionFactory server = new TcpNetServerConnectionFactory(0); server.setBeanName("server"); + server.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); server.setBeanFactory(TEST_INTEGRATION_CONTEXT); server.afterPropertiesSet(); DirectChannel inChannel = new DirectChannel(); @@ -477,6 +486,9 @@ public void testFailoverCachedWithGateway() { int port = server.getPort(); AbstractClientConnectionFactory client = new TcpNetClientConnectionFactory("localhost", port); client.setBeanName("client"); + client.setBeanFactory(TEST_INTEGRATION_CONTEXT); + client.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + client.afterPropertiesSet(); // Cache CachingClientConnectionFactory cachingClient = new CachingClientConnectionFactory(client, 2); @@ -520,21 +532,28 @@ public void testFailoverCachedWithGateway() { public void testFailoverCachedRealBadHost() throws Exception { TcpNetServerConnectionFactory server1 = new TcpNetServerConnectionFactory(0); server1.setBeanName("server1"); + server1.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + server1.setBeanFactory(TEST_INTEGRATION_CONTEXT); final CountDownLatch latch1 = new CountDownLatch(3); server1.registerListener(message -> { latch1.countDown(); return false; }); + server1.afterPropertiesSet(); server1.start(); TestingUtilities.waitListening(server1, 10000L); int port1 = server1.getPort(); + TcpNetServerConnectionFactory server2 = new TcpNetServerConnectionFactory(0); server2.setBeanName("server2"); + server2.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + server2.setBeanFactory(TEST_INTEGRATION_CONTEXT); final CountDownLatch latch2 = new CountDownLatch(2); server2.registerListener(message -> { latch2.countDown(); return false; }); + server2.afterPropertiesSet(); server2.start(); TestingUtilities.waitListening(server2, 10000L); int port2 = server2.getPort(); @@ -542,9 +561,16 @@ public void testFailoverCachedRealBadHost() throws Exception { AbstractClientConnectionFactory factory1 = new TcpNetClientConnectionFactory("junkjunk", port1); factory1.setBeanName("client1"); factory1.registerListener(message -> false); + factory1.setBeanFactory(TEST_INTEGRATION_CONTEXT); + factory1.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + factory1.afterPropertiesSet(); + AbstractClientConnectionFactory factory2 = new TcpNetClientConnectionFactory("localhost", port2); factory2.setBeanName("client2"); factory2.registerListener(message -> false); + factory2.setBeanFactory(TEST_INTEGRATION_CONTEXT); + factory2.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + factory2.afterPropertiesSet(); // Cache CachingClientConnectionFactory cachingFactory1 = new CachingClientConnectionFactory(factory1, 2); @@ -591,10 +617,14 @@ private void testRealGuts(AbstractClientConnectionFactory client1, AbstractClien client2.setTaskExecutor(holder.exec); client1.setBeanName("client1"); client2.setBeanName("client2"); + client1.setBeanFactory(TEST_INTEGRATION_CONTEXT); + client2.setBeanFactory(TEST_INTEGRATION_CONTEXT); client1.setApplicationEventPublisher(event -> { }); client2.setApplicationEventPublisher(event -> { }); + client1.afterPropertiesSet(); + client2.afterPropertiesSet(); List factories = new ArrayList<>(); factories.add(client1); factories.add(client2); @@ -642,10 +672,12 @@ private Holder setupAndStartServers(AbstractServerConnectionFactory server1, server2.setTaskExecutor(exec); server1.setBeanName("server1"); server2.setBeanName("server2"); - server1.setApplicationEventPublisher(event -> { - }); - server2.setApplicationEventPublisher(event -> { - }); + server1.setBeanFactory(TEST_INTEGRATION_CONTEXT); + server2.setBeanFactory(TEST_INTEGRATION_CONTEXT); + server1.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + server2.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + server1.afterPropertiesSet(); + server2.afterPropertiesSet(); TcpInboundGateway gateway1 = new TcpInboundGateway(); gateway1.setConnectionFactory(server1); SubscribableChannel channel = new DirectChannel(); diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/SocketSupportTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/SocketSupportTests.java index a3d14b99709..77e473e4329 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/SocketSupportTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/SocketSupportTests.java @@ -43,6 +43,7 @@ import org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer; import org.springframework.integration.ip.util.TestingUtilities; +import org.springframework.integration.test.support.TestApplicationContextAware; import org.springframework.integration.test.util.TestUtils; import org.springframework.messaging.Message; import org.springframework.messaging.MessagingException; @@ -67,7 +68,7 @@ * * @since 2.2 */ -public class SocketSupportTests { +public class SocketSupportTests implements TestApplicationContextAware { @Test public void testNetClient() throws Exception { @@ -86,6 +87,9 @@ public void testNetClient() throws Exception { TcpNetClientConnectionFactory connectionFactory = new TcpNetClientConnectionFactory("x", 0); connectionFactory.setTcpSocketFactorySupport(factorySupport); connectionFactory.setTcpSocketSupport(socketSupport); + connectionFactory.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + connectionFactory.setBeanFactory(TEST_INTEGRATION_CONTEXT); + connectionFactory.afterPropertiesSet(); connectionFactory.start(); connectionFactory.getConnection(); @@ -112,6 +116,9 @@ public void testNetClientSocketTimeout() throws Exception { connectionFactory.setConnectTimeout(1); connectionFactory.setTcpSocketFactorySupport(factorySupport); connectionFactory.setTcpSocketSupport(socketSupport); + connectionFactory.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + connectionFactory.setBeanFactory(TEST_INTEGRATION_CONTEXT); + connectionFactory.afterPropertiesSet(); connectionFactory.start(); assertThatThrownBy(connectionFactory::getConnection) .isInstanceOf(UncheckedIOException.class) @@ -159,6 +166,9 @@ public void testNetServer() throws Exception { connectionFactory.setTcpSocketFactorySupport(factorySupport); connectionFactory.setTcpSocketSupport(socketSupport); connectionFactory.registerListener(mock(TcpListener.class)); + connectionFactory.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + connectionFactory.setBeanFactory(TEST_INTEGRATION_CONTEXT); + connectionFactory.afterPropertiesSet(); connectionFactory.start(); assertThat(latch1.await(10, TimeUnit.SECONDS)).isTrue(); @@ -190,6 +200,9 @@ public void postProcessServerSocket(ServerSocket serverSocket) { }; serverConnectionFactory.setTcpSocketSupport(serverSocketSupport); + serverConnectionFactory.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + serverConnectionFactory.setBeanFactory(TEST_INTEGRATION_CONTEXT); + serverConnectionFactory.afterPropertiesSet(); serverConnectionFactory.start(); TestingUtilities.waitListening(serverConnectionFactory, null); @@ -211,6 +224,9 @@ public void postProcessServerSocket(ServerSocket serverSocket) { }; clientConnectionFactory.setTcpSocketSupport(clientSocketSupport); + clientConnectionFactory.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + clientConnectionFactory.setBeanFactory(TEST_INTEGRATION_CONTEXT); + clientConnectionFactory.afterPropertiesSet(); clientConnectionFactory.start(); clientConnectionFactory.getConnection().send(new GenericMessage<>("Hello, world!")); assertThat(latch.await(10, TimeUnit.SECONDS)).isTrue(); @@ -377,7 +393,6 @@ public void postProcessServerSocket(ServerSocket serverSocket) { */ @Test public void testNetClientAndServerSSL() throws Exception { - System.setProperty("javax.net.debug", "all"); // SSL activity in the console TcpNetServerConnectionFactory server = new TcpNetServerConnectionFactory(0); TcpSSLContextSupport sslContextSupport = new DefaultTcpSSLContextSupport("test.ks", "test.truststore.ks", "secret", "secret"); @@ -391,13 +406,21 @@ public void testNetClientAndServerSSL() throws Exception { latch.countDown(); return false; }); - server.setMapper(new SSLMapper()); + SSLMapper mapper = new SSLMapper(); + mapper.setBeanFactory(TEST_INTEGRATION_CONTEXT); + server.setMapper(mapper); + server.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + server.setBeanFactory(TEST_INTEGRATION_CONTEXT); + server.afterPropertiesSet(); server.start(); TestingUtilities.waitListening(server, null); TcpNetClientConnectionFactory client = new TcpNetClientConnectionFactory("localhost", server.getPort()); client.setTcpSocketFactorySupport(tcpSocketFactorySupport); client.setTcpSocketSupport(new DefaultTcpSocketSupport(true)); + client.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + client.setBeanFactory(TEST_INTEGRATION_CONTEXT); + client.afterPropertiesSet(); client.start(); TcpConnection connection = client.getConnection(); @@ -418,7 +441,6 @@ public void testNetClientAndServerSSLDifferentContexts() throws Exception { } private void testNetClientAndServerSSLDifferentContexts(boolean badServer) throws Exception { - System.setProperty("javax.net.debug", "all"); // SSL activity in the console TcpNetServerConnectionFactory server = new TcpNetServerConnectionFactory(0); TcpSSLContextSupport serverSslContextSupport = new DefaultTcpSSLContextSupport( badServer ? "client.ks" : "server.ks", @@ -443,6 +465,9 @@ public void postProcessServerSocket(ServerSocket serverSocket) { } }); + server.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + server.setBeanFactory(TEST_INTEGRATION_CONTEXT); + server.afterPropertiesSet(); server.start(); TestingUtilities.waitListening(server, null); @@ -453,6 +478,9 @@ public void postProcessServerSocket(ServerSocket serverSocket) { new DefaultTcpNetSSLSocketFactorySupport(clientSslContextSupport); client.setTcpSocketFactorySupport(clientTcpSocketFactorySupport); client.setTcpSocketSupport(new DefaultTcpSocketSupport(false)); + client.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + client.setBeanFactory(TEST_INTEGRATION_CONTEXT); + client.afterPropertiesSet(); try { client.start(); @@ -469,7 +497,6 @@ public void postProcessServerSocket(ServerSocket serverSocket) { @Test public void testNioClientAndServerSSL() throws Exception { - System.setProperty("javax.net.debug", "all"); // SSL activity in the console TcpNioServerConnectionFactory server = new TcpNioServerConnectionFactory(0); server.setTaskScheduler(new SimpleAsyncTaskScheduler()); server.setSslHandshakeTimeout(43); @@ -486,13 +513,17 @@ public void testNioClientAndServerSSL() throws Exception { latch.countDown(); return false; }); - server.setMapper(new SSLMapper()); + SSLMapper mapper = new SSLMapper(); + mapper.setBeanFactory(TEST_INTEGRATION_CONTEXT); + server.setMapper(mapper); final AtomicReference serverConnectionId = new AtomicReference<>(); server.setApplicationEventPublisher(e -> { if (e instanceof TcpConnectionOpenEvent) { serverConnectionId.set(((TcpConnectionEvent) e).getConnectionId()); } }); + server.setBeanFactory(TEST_INTEGRATION_CONTEXT); + server.afterPropertiesSet(); server.start(); TestingUtilities.waitListening(server, null); @@ -500,8 +531,9 @@ public void testNioClientAndServerSSL() throws Exception { client.setSslHandshakeTimeout(34); client.setTcpNioConnectionSupport(tcpNioConnectionSupport); client.registerListener(message -> false); - client.setApplicationEventPublisher(e -> { - }); + client.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + client.setBeanFactory(TEST_INTEGRATION_CONTEXT); + client.afterPropertiesSet(); client.start(); TcpConnection connection = client.getConnection(); @@ -529,7 +561,6 @@ public void testNioClientAndServerSSLDifferentContexts() throws Exception { } private void testNioClientAndServerSSLDifferentContexts(boolean badServer) throws Exception { - System.setProperty("javax.net.debug", "all"); // SSL activity in the console TcpNioServerConnectionFactory server = new TcpNioServerConnectionFactory(0); TcpSSLContextSupport serverSslContextSupport = new DefaultTcpSSLContextSupport( badServer ? "client.ks" : "server.ks", @@ -551,6 +582,9 @@ protected void postProcessSSLEngine(SSLEngine sslEngine) { latch.countDown(); return false; }); + server.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + server.setBeanFactory(TEST_INTEGRATION_CONTEXT); + server.afterPropertiesSet(); server.start(); TestingUtilities.waitListening(server, null); @@ -560,6 +594,9 @@ protected void postProcessSSLEngine(SSLEngine sslEngine) { DefaultTcpNioSSLConnectionSupport clientTcpNioConnectionSupport = new DefaultTcpNioSSLConnectionSupport(clientSslContextSupport, false); client.setTcpNioConnectionSupport(clientTcpNioConnectionSupport); + client.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + client.setBeanFactory(TEST_INTEGRATION_CONTEXT); + client.afterPropertiesSet(); try { client.start(); @@ -576,7 +613,6 @@ protected void postProcessSSLEngine(SSLEngine sslEngine) { @Test public void testNioClientAndServerSSLDifferentContextsLargeDataWithReply() throws Exception { - System.setProperty("javax.net.debug", "all"); // SSL activity in the console TcpNioServerConnectionFactory server = new TcpNioServerConnectionFactory(0); server.setTaskScheduler(new SimpleAsyncTaskScheduler()); TcpSSLContextSupport serverSslContextSupport = new DefaultTcpSSLContextSupport("server.ks", @@ -608,6 +644,8 @@ public void testNioClientAndServerSSLDifferentContextsLargeDataWithReply() throw serverConnectionId.set(((TcpConnectionEvent) e).getConnectionId()); } }); + server.setBeanFactory(TEST_INTEGRATION_CONTEXT); + server.afterPropertiesSet(); server.start(); TestingUtilities.waitListening(server, null); @@ -623,8 +661,9 @@ public void testNioClientAndServerSSLDifferentContextsLargeDataWithReply() throw return false; }); client.setDeserializer(deserializer); - client.setApplicationEventPublisher(e -> { - }); + client.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + client.setBeanFactory(TEST_INTEGRATION_CONTEXT); + client.afterPropertiesSet(); client.start(); TcpConnection connection = client.getConnection(); diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpMessageMapperTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpMessageMapperTests.java index dbbf4cb614b..ac551987925 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpMessageMapperTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpMessageMapperTests.java @@ -73,6 +73,7 @@ public void setup() { @Test public void testToMessage() { TcpMessageMapper mapper = new TcpMessageMapper(); + mapper.setBeanFactory(mock()); TcpConnection connection = creatMockTcpConcnection(TEST_PAYLOAD.getBytes(), "MyHost", "1.1.1.1", 1234); InetAddress local = mock(InetAddress.class); Socket socket = creatMockSocket(local); @@ -91,6 +92,7 @@ public void testToMessage() { public void testToMessageWithContentType() { TcpMessageMapper mapper = new TcpMessageMapper(); mapper.setAddContentTypeHeader(true); + mapper.setBeanFactory(mock()); TcpConnection connection = creatMockTcpConcnection(TEST_PAYLOAD.getBytes(), "MyHost", "1.1.1.1", 1234); InetAddress local = mock(InetAddress.class); Socket socket = creatMockSocket(local); @@ -113,6 +115,7 @@ public void testToMessageWithCustomContentType() { TcpMessageMapper mapper = new TcpMessageMapper(); mapper.setAddContentTypeHeader(true); mapper.setContentType("application/octet-stream;charset=ISO-8859-1"); + mapper.setBeanFactory(mock()); TcpConnection connection = creatMockTcpConcnection(TEST_PAYLOAD.getBytes(), "MyHost", "1.1.1.1", 1234); InetAddress local = mock(InetAddress.class); Socket socket = creatMockSocket(local); @@ -142,6 +145,7 @@ public void testToMessageWithBadContentType() { @Test public void testToMessageSequence() throws Exception { TcpMessageMapper mapper = new TcpMessageMapper(); + mapper.setBeanFactory(mock()); Socket socket = SocketFactory.getDefault().createSocket(); TcpConnection connection = new TcpConnectionSupport(socket, false, false, null, null) { @@ -225,6 +229,7 @@ public void testToMessageSequenceNewWithCustomHeader() throws Exception { }; mapper.setApplySequence(true); + mapper.setBeanFactory(mock()); Socket socket = SocketFactory.getDefault().createSocket(); TcpConnection connection = new TcpConnectionSupport(socket, false, false, null, null) { @@ -414,6 +419,7 @@ public void testWithBytesMapper() { .build(); TcpMessageMapper mapper = new TcpMessageMapper(); mapper.setBytesMessageMapper(new EmbeddedHeadersJsonMessageMapper()); + mapper.setBeanFactory(mock()); byte[] bytes = (byte[]) mapper.fromMessage(outMessage); TcpConnection connection = creatMockTcpConcnection(bytes, "someHost", "1.1.1.1", 1234); diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionReadTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionReadTests.java index f8f366e045e..1dd6b14a9b5 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionReadTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionReadTests.java @@ -36,6 +36,7 @@ import org.springframework.integration.ip.tcp.serializer.ByteArrayStxEtxSerializer; import org.springframework.integration.ip.util.SocketTestUtils; import org.springframework.integration.ip.util.TestingUtilities; +import org.springframework.integration.test.support.TestApplicationContextAware; import org.springframework.messaging.Message; import org.springframework.messaging.support.ErrorMessage; import org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler; @@ -49,7 +50,7 @@ * * @since 2.0 */ -public class TcpNioConnectionReadTests { +public class TcpNioConnectionReadTests implements TestApplicationContextAware { private final CountDownLatch latch = new CountDownLatch(1); @@ -73,6 +74,8 @@ private AbstractServerConnectionFactory getConnectionFactory( if (sender != null) { scf.registerSender(sender); } + scf.setBeanFactory(TEST_INTEGRATION_CONTEXT); + scf.afterPropertiesSet(); scf.start(); TestingUtilities.waitListening(scf, null); return scf; diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionTests.java index 9cae80eb4d1..541859cc805 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/tcp/connection/TcpNioConnectionTests.java @@ -365,7 +365,9 @@ public void testSufficientThreads() throws Exception { messageLatch.countDown(); return false; }); - connection.setMapper(new TcpMessageMapper()); + TcpMessageMapper mapper = new TcpMessageMapper(); + mapper.setBeanFactory(TEST_INTEGRATION_CONTEXT); + connection.setMapper(mapper); connection.setDeserializer(new ByteArrayCrLfSerializer()); Method method = TcpNioConnection.class.getDeclaredMethod("doRead"); method.setAccessible(true); @@ -560,6 +562,8 @@ public void testAssemblerUsesSecondaryExecutor() throws Exception { } return false; }); + factory.setBeanFactory(TEST_INTEGRATION_CONTEXT); + factory.afterPropertiesSet(); factory.start(); TestingUtilities.waitListening(factory, null); int port = factory.getPort(); @@ -615,6 +619,8 @@ public void testAllMessagesDelivered() throws Exception { } return false; }); + factory.setBeanFactory(TEST_INTEGRATION_CONTEXT); + factory.afterPropertiesSet(); factory.start(); TestingUtilities.waitListening(factory, null); int port = factory.getPort(); @@ -708,7 +714,7 @@ public void publishEvent(Object event) { }); final CountDownLatch assemblerLatch = new CountDownLatch(1); - final AtomicReference assembler = new AtomicReference(); + final AtomicReference assembler = new AtomicReference<>(); factory.registerListener(message -> { if (!(message instanceof ErrorMessage)) { assembler.set(Thread.currentThread()); @@ -722,6 +728,8 @@ public void publishEvent(Object event) { te.setQueueCapacity(0); te.initialize(); factory.setTaskExecutor(te); + factory.setBeanFactory(TEST_INTEGRATION_CONTEXT); + factory.afterPropertiesSet(); factory.start(); TestingUtilities.waitListening(factory, 10000L); int port = factory.getPort(); diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/DatagramPacketMessageMapperTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/DatagramPacketMessageMapperTests.java index c96e9583aaa..1230241ed8b 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/DatagramPacketMessageMapperTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/DatagramPacketMessageMapperTests.java @@ -28,7 +28,8 @@ import org.springframework.messaging.Message; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.mockito.Mockito.mock; /** * @author Gary Russell @@ -65,6 +66,7 @@ private void test(boolean ack, boolean lengthCheck) { mapper.setAckAddress("localhost:11111"); mapper.setAcknowledge(ack); mapper.setLengthCheck(lengthCheck); + mapper.setBeanFactory(mock()); DatagramPacket packet = mapper.fromMessage(message); packet.setSocketAddress(new InetSocketAddress("localhost", 22222)); Message messageOut = mapper.toMessage(packet); @@ -98,13 +100,10 @@ public void testTruncation() { int bigLen = 99999; bb.putInt(bigLen); packet.setSocketAddress(new InetSocketAddress("localhost", 22222)); - try { - mapper.toMessage(packet); - fail("Truncated message exception expected"); - } - catch (MessageMappingException e) { - assertThat(e.getMessage()).contains("expected " + (bigLen + 4) + ", received " + (test.length() + 4)); - } + + assertThatExceptionOfType(MessageMappingException.class) + .isThrownBy(() -> mapper.toMessage(packet)) + .withMessageContaining("expected " + (bigLen + 4) + ", received " + (test.length() + 4)); } } diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/DatagramPacketMulticastSendingHandlerTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/DatagramPacketMulticastSendingHandlerTests.java index ca532f48a92..30f89f09b5a 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/DatagramPacketMulticastSendingHandlerTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/DatagramPacketMulticastSendingHandlerTests.java @@ -161,6 +161,7 @@ public void verifySendMulticastWithAcks(MulticastCondition multicastCondition) t DatagramPacketMessageMapper mapper = new DatagramPacketMessageMapper(); mapper.setAcknowledge(true); mapper.setLengthCheck(true); + mapper.setBeanFactory(TEST_INTEGRATION_CONTEXT); Message message = mapper.toMessage(receivedPacket); Object id = message.getHeaders().get(IpHeaders.ACK_ID); byte[] ack = id.toString().getBytes(); diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/DatagramPacketSendingHandlerTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/DatagramPacketSendingHandlerTests.java index 7820aa4313c..c6e84f14e27 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/DatagramPacketSendingHandlerTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/DatagramPacketSendingHandlerTests.java @@ -104,6 +104,7 @@ public void verifySendWithAck() throws Exception { DatagramPacketMessageMapper mapper = new DatagramPacketMessageMapper(); mapper.setAcknowledge(true); mapper.setLengthCheck(true); + mapper.setBeanFactory(TEST_INTEGRATION_CONTEXT); Message message = mapper.toMessage(receivedPacket); Object id = message.getHeaders().get(IpHeaders.ACK_ID); byte[] ack = id.toString().getBytes(); diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/MulticastCondition.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/MulticastCondition.java index f2a9a935e7f..a3773a71ae0 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/MulticastCondition.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/MulticastCondition.java @@ -33,7 +33,6 @@ import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotations; import org.springframework.integration.ip.util.SocketTestUtils; -import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** @@ -52,7 +51,6 @@ public class MulticastCondition implements BeforeAllCallback, ParameterResolver private String group; - @Nullable private NetworkInterface nic; private boolean skip; @@ -73,7 +71,6 @@ public void checkMulticast(String group) { } } - @Nullable private NetworkInterface doCheckMulticast(String group) throws Exception { NetworkInterface nic = SocketTestUtils.chooseANic(true); if (nic == null) { // no multicast support @@ -96,7 +93,6 @@ public String getGroup() { return group; } - @Nullable public NetworkInterface getNic() { return nic; } diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/SyslogdTests-context.xml b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/SyslogdTests-context.xml deleted file mode 100644 index 57391b57976..00000000000 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/SyslogdTests-context.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/SyslogdTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/SyslogdTests.java deleted file mode 100644 index 3053665b40a..00000000000 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/SyslogdTests.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2002-present 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.integration.ip.udp; - -import org.springframework.context.support.AbstractApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -/** - * @author Gary Russell - * @since 2.2 - * - */ -public class SyslogdTests { - - private SyslogdTests() { - super(); - } - - public static void main(String[] args) throws Exception { - AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("SyslogdTests-context.xml", SyslogdTests.class); - // System . out . println("Hit enter to terminate"); - System.in.read(); - ctx.close(); - } - -} diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpChannelAdapterTests.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpChannelAdapterTests.java index 338464b530a..23056918ad3 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpChannelAdapterTests.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/udp/UdpChannelAdapterTests.java @@ -143,6 +143,9 @@ public Executor getTaskExecutor() { if (useLocalAddress) { adapter.setLocalAddress("127.0.0.1"); } + adapter.setBeanFactory(TEST_INTEGRATION_CONTEXT); + adapter.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + adapter.afterPropertiesSet(); adapter.start(); SocketTestUtils.waitListening(adapter); int port = adapter.getPort(); @@ -172,6 +175,9 @@ public void testUnicastReceiverWithReply() throws Exception { QueueChannel channel = new QueueChannel(2); UnicastReceivingChannelAdapter adapter = new UnicastReceivingChannelAdapter(0); adapter.setOutputChannel(channel); + adapter.setBeanFactory(TEST_INTEGRATION_CONTEXT); + adapter.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + adapter.afterPropertiesSet(); adapter.start(); SocketTestUtils.waitListening(adapter); int port = adapter.getPort(); @@ -182,7 +188,7 @@ public void testUnicastReceiverWithReply() throws Exception { packet.setSocketAddress(new InetSocketAddress("localhost", port)); final DatagramSocket socket = new DatagramSocket(0); socket.send(packet); - final AtomicReference theAnswer = new AtomicReference(); + final AtomicReference theAnswer = new AtomicReference<>(); final CountDownLatch receiverReadyLatch = new CountDownLatch(1); final CountDownLatch replyReceivedLatch = new CountDownLatch(1); //main thread sends the reply using the headers, this thread will receive it @@ -226,6 +232,9 @@ public void testUnicastSender() { UnicastReceivingChannelAdapter adapter = new UnicastReceivingChannelAdapter(0); adapter.setBeanName("test"); adapter.setOutputChannel(channel); + adapter.setBeanFactory(TEST_INTEGRATION_CONTEXT); + adapter.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + adapter.afterPropertiesSet(); adapter.start(); SocketTestUtils.waitListening(adapter); int port = adapter.getPort(); @@ -257,6 +266,9 @@ public void testMulticastReceiver(MulticastCondition multicastCondition) throws if (nic != null) { adapter.setLocalAddress(nic.getInetAddresses().nextElement().getHostName()); } + adapter.setBeanFactory(TEST_INTEGRATION_CONTEXT); + adapter.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + adapter.afterPropertiesSet(); adapter.start(); SocketTestUtils.waitListening(adapter); int port = adapter.getPort(); @@ -303,6 +315,9 @@ public void testMulticastSender(MulticastCondition multicastCondition) { if (nic != null) { adapter.setLocalAddress(nic.getInetAddresses().nextElement().getHostName()); } + adapter.setBeanFactory(TEST_INTEGRATION_CONTEXT); + adapter.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + adapter.afterPropertiesSet(); adapter.start(); SocketTestUtils.waitListening(adapter); @@ -332,6 +347,9 @@ public void testUnicastReceiverException() throws Exception { channel.subscribe(handler); QueueChannel errorChannel = new QueueChannel(); adapter.setErrorChannel(errorChannel); + adapter.setBeanFactory(TEST_INTEGRATION_CONTEXT); + adapter.setApplicationEventPublisher(TEST_INTEGRATION_CONTEXT); + adapter.afterPropertiesSet(); adapter.start(); SocketTestUtils.waitListening(adapter); int port = adapter.getPort(); diff --git a/spring-integration-ip/src/test/java/org/springframework/integration/ip/util/SocketTestUtils.java b/spring-integration-ip/src/test/java/org/springframework/integration/ip/util/SocketTestUtils.java index af7c31a8085..f7d75413ed6 100644 --- a/spring-integration-ip/src/test/java/org/springframework/integration/ip/util/SocketTestUtils.java +++ b/spring-integration-ip/src/test/java/org/springframework/integration/ip/util/SocketTestUtils.java @@ -33,7 +33,6 @@ import org.apache.commons.logging.LogFactory; import org.springframework.integration.ip.AbstractInternetProtocolReceivingChannelAdapter; -import org.springframework.lang.Nullable; import static org.awaitility.Awaitility.await; @@ -349,7 +348,6 @@ public static void setLocalNicIfPossible( } } - @Nullable public static NetworkInterface chooseANic(boolean multicast) throws Exception { Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { diff --git a/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterFactoryBean.java b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterFactoryBean.java index b3daea3fbc8..c5270fb34be 100644 --- a/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterFactoryBean.java +++ b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/config/SyslogReceivingChannelAdapterFactoryBean.java @@ -18,6 +18,7 @@ import org.jspecify.annotations.Nullable; +import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.config.AbstractFactoryBean; import org.springframework.context.ApplicationEventPublisher; @@ -184,28 +185,38 @@ public Class getObjectType() { @Override protected SyslogReceivingChannelAdapterSupport createInstance() { SyslogReceivingChannelAdapterSupport adapter; + UnicastReceivingChannelAdapter udpAdapterToUse = this.udpAdapter; + BeanFactory beanFactory = getBeanFactory(); + ApplicationEventPublisher applicationEventPublisherToUse = this.applicationEventPublisher; if (this.protocol == Protocol.tcp) { adapter = new TcpSyslogReceivingChannelAdapter(); if (this.connectionFactory != null) { Assert.isNull(this.port, "Cannot specify both 'port' and 'connectionFactory'"); ((TcpSyslogReceivingChannelAdapter) adapter).setConnectionFactory(this.connectionFactory); } - else if (this.applicationEventPublisher != null) { + else if (applicationEventPublisherToUse != null) { ((TcpSyslogReceivingChannelAdapter) adapter) - .setApplicationEventPublisher(this.applicationEventPublisher); + .setApplicationEventPublisher(applicationEventPublisherToUse); } - Assert.isNull(this.udpAdapter, "Cannot specify 'udp-attributes' when the protocol is 'tcp'"); + Assert.isNull(udpAdapterToUse, "Cannot specify 'udp-attributes' when the protocol is 'tcp'"); } else if (this.protocol == Protocol.udp) { adapter = new UdpSyslogReceivingChannelAdapter(); - if (this.udpAdapter != null) { + if (udpAdapterToUse != null) { Assert.isNull(this.port, "Cannot specify both 'port' and 'udpAdapter'"); - ((UdpSyslogReceivingChannelAdapter) adapter).setUdpAdapter(this.udpAdapter); + if (beanFactory != null) { + udpAdapterToUse.setBeanFactory(beanFactory); + } + if (applicationEventPublisherToUse != null) { + udpAdapterToUse.setApplicationEventPublisher(applicationEventPublisherToUse); + } + udpAdapterToUse.afterPropertiesSet(); + ((UdpSyslogReceivingChannelAdapter) adapter).setUdpAdapter(udpAdapterToUse); } Assert.isNull(this.connectionFactory, "Cannot specify 'connection-factory' unless the protocol is 'tcp'"); } else { - throw new IllegalStateException("Unsupported protocol: " + this.protocol.toString()); + throw new IllegalStateException("Unsupported protocol: " + this.protocol); } adapter.setAutoStartup(this.autoStartup); @@ -218,7 +229,8 @@ else if (this.protocol == Protocol.udp) { .acceptIfNotNull(this.sendTimeout, adapter::setSendTimeout) .acceptIfNotNull(this.converter, adapter::setConverter) .acceptIfNotNull(this.beanName, adapter::setBeanName) - .acceptIfNotNull(getBeanFactory(), adapter::setBeanFactory); + .acceptIfNotNull(beanFactory, adapter::setBeanFactory) + .acceptIfNotNull(applicationEventPublisherToUse, adapter::setApplicationEventPublisher); adapter.afterPropertiesSet(); this.syslogAdapter = adapter; diff --git a/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/SyslogReceivingChannelAdapterSupport.java b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/SyslogReceivingChannelAdapterSupport.java index dc2560c9ea3..a540d415f81 100644 --- a/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/SyslogReceivingChannelAdapterSupport.java +++ b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/SyslogReceivingChannelAdapterSupport.java @@ -16,6 +16,8 @@ package org.springframework.integration.syslog.inbound; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.integration.endpoint.MessageProducerSupport; import org.springframework.integration.syslog.DefaultMessageConverter; import org.springframework.integration.syslog.MessageConverter; @@ -28,19 +30,34 @@ * * @author Gary Russell * @author Ngoc Nhan + * @author Artem Bilan + * * @since 3.0 * */ -public abstract class SyslogReceivingChannelAdapterSupport extends MessageProducerSupport { +public abstract class SyslogReceivingChannelAdapterSupport extends MessageProducerSupport + implements ApplicationEventPublisherAware { protected static final int DEFAULT_PORT = 514; + @SuppressWarnings("NullAway.Init") + private ApplicationEventPublisher applicationEventPublisher; + private volatile int port = DEFAULT_PORT; private MessageConverter converter = new DefaultMessageConverter(); private boolean converterSet; + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { + this.applicationEventPublisher = applicationEventPublisher; + } + + protected ApplicationEventPublisher getApplicationEventPublisher() { + return this.applicationEventPublisher; + } + /** * @return The port on which this adapter listens. */ diff --git a/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/UdpSyslogReceivingChannelAdapter.java b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/UdpSyslogReceivingChannelAdapter.java index d12647a1826..a1c1608fe2d 100644 --- a/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/UdpSyslogReceivingChannelAdapter.java +++ b/spring-integration-syslog/src/main/java/org/springframework/integration/syslog/inbound/UdpSyslogReceivingChannelAdapter.java @@ -61,6 +61,7 @@ protected void onInit() { if (this.udpAdapter == null) { this.udpAdapter = new UnicastReceivingChannelAdapter(getPort()); this.udpAdapter.setBeanFactory(getBeanFactory()); + this.udpAdapter.setApplicationEventPublisher(getApplicationEventPublisher()); } else { logger.info("The 'UdpSyslogReceivingChannelAdapter' overrides an 'outputChannel' " + diff --git a/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/inbound/SyslogReceivingChannelAdapterTests.java b/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/inbound/SyslogReceivingChannelAdapterTests.java index e282a315b83..5fd052eef10 100644 --- a/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/inbound/SyslogReceivingChannelAdapterTests.java +++ b/spring-integration-syslog/src/test/java/org/springframework/integration/syslog/inbound/SyslogReceivingChannelAdapterTests.java @@ -77,6 +77,7 @@ public void testUdp() throws Exception { factory.setPort(0); factory.setOutputChannel(outputChannel); factory.setBeanFactory(mock()); + factory.setApplicationEventPublisher(mock()); factory.afterPropertiesSet(); factory.start(); UnicastReceivingChannelAdapter server = TestUtils.getPropertyValue(factory, "syslogAdapter.udpAdapter", @@ -150,6 +151,7 @@ public void testAsMapFalse() throws Exception { PollableChannel outputChannel = new QueueChannel(); factory.setOutputChannel(outputChannel); factory.setBeanFactory(mock()); + factory.setApplicationEventPublisher(mock()); factory.afterPropertiesSet(); factory.start(); UnicastReceivingChannelAdapter server = TestUtils.getPropertyValue(factory, "syslogAdapter.udpAdapter", @@ -191,10 +193,12 @@ public void testTcpRFC5424() throws Exception { return null; }).when(publisher).publishEvent(any(ApplicationEvent.class)); factory.setBeanFactory(getBeanFactory()); + factory.setApplicationEventPublisher(publisher); AbstractServerConnectionFactory connectionFactory = new TcpNioServerConnectionFactory(0); connectionFactory.setBeanFactory(getBeanFactory()); connectionFactory.setDeserializer(new RFC6587SyslogDeserializer()); connectionFactory.setApplicationEventPublisher(publisher); + connectionFactory.afterPropertiesSet(); factory.setConnectionFactory(connectionFactory); factory.setConverter(new RFC5424MessageConverter()); factory.afterPropertiesSet(); @@ -239,11 +243,12 @@ public void testUdpRFC5424() throws Exception { PollableChannel outputChannel = new QueueChannel(); factory.setOutputChannel(outputChannel); factory.setConverter(new RFC5424MessageConverter()); + factory.setBeanFactory(mock()); + factory.setApplicationEventPublisher(mock()); factory.afterPropertiesSet(); factory.start(); UnicastReceivingChannelAdapter server = TestUtils.getPropertyValue(factory, "syslogAdapter.udpAdapter", UnicastReceivingChannelAdapter.class); - server.setBeanFactory(mock()); TestingUtilities.waitListening(server, null); UdpSyslogReceivingChannelAdapter adapter = (UdpSyslogReceivingChannelAdapter) factory.getObject(); byte[] buf = ("<14>1 2014-06-20T09:14:07+00:00 loggregator d0602076-b14a-4c55-852a-981e7afeed38 DEA - " +