Make IOS.setTaskScheduler() as public (#2725)

* Make IOS.setTaskScheduler() as public

* Make `IntegrationObjectSupport.setTaskScheduler()` as `public` and
remove all the overrides for visibility
* Fix Sonar smells for all the affected classes

* * Fix `throws Exception` for affected classes to avoid compilation errors

* * Fix "merely rethrow" smell
* Revert `throws Exception` for `AbstractEndpoint.destroy()`

* * Catch a couple exceptions from `destroy()`
This commit is contained in:
Artem Bilan
2019-01-30 13:59:37 -05:00
committed by Gary Russell
parent 7980afef9b
commit 020ea76d59
10 changed files with 158 additions and 151 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
@@ -28,8 +28,6 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.locks.Lock;
import org.aopalliance.aop.Advice;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.BeanFactory;
@@ -57,7 +55,6 @@ import org.springframework.integration.util.UUIDConverter;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageDeliveryException;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
@@ -96,8 +93,6 @@ import org.springframework.util.CollectionUtils;
public abstract class AbstractCorrelatingMessageHandler extends AbstractMessageProducingHandler
implements DiscardingMessageHandler, DisposableBean, ApplicationEventPublisherAware, Lifecycle {
protected final Log logger = LogFactory.getLog(getClass());
private final Comparator<Message<?>> sequenceNumberComparator = new MessageSequenceComparator();
private final Map<UUID, ScheduledFuture<?>> expireGroupScheduledFutures = new ConcurrentHashMap<>();
@@ -286,11 +281,6 @@ public abstract class AbstractCorrelatingMessageHandler extends AbstractMessageP
this.popSequence = popSequence;
}
@Override
public void setTaskScheduler(TaskScheduler taskScheduler) {
super.setTaskScheduler(taskScheduler);
}
protected boolean isReleaseLockBeforeSend() {
return this.releaseLockBeforeSend;
}
@@ -444,7 +434,7 @@ public abstract class AbstractCorrelatingMessageHandler extends AbstractMessageP
}
@Override
protected void handleMessageInternal(Message<?> message) throws Exception {
protected void handleMessageInternal(Message<?> message) throws InterruptedException {
Object correlationKey = this.correlationStrategy.getCorrelationKey(message);
Assert.state(correlationKey != null,
"Null correlation not allowed. Maybe the CorrelationStrategy is failing?");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2018 the original author or authors.
* Copyright 2013-2019 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.
@@ -30,7 +30,6 @@ import org.springframework.integration.context.IntegrationObjectSupport;
import org.springframework.integration.support.channel.HeaderChannelRegistry;
import org.springframework.lang.Nullable;
import org.springframework.messaging.MessageChannel;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.util.Assert;
/**
@@ -53,11 +52,11 @@ public class DefaultHeaderChannelRegistry extends IntegrationObjectSupport
private static final int DEFAULT_REAPER_DELAY = 60000;
protected static final AtomicLong id = new AtomicLong();
protected static final AtomicLong id = new AtomicLong(); // NOSONAR
protected final Map<String, MessageChannelWrapper> channels = new ConcurrentHashMap<>();
protected final Map<String, MessageChannelWrapper> channels = new ConcurrentHashMap<>(); // NOSONAR
protected final String uuid = UUID.randomUUID().toString() + ":";
protected final String uuid = UUID.randomUUID().toString() + ":"; // NOSONAR
private boolean removeOnGet;
@@ -108,11 +107,6 @@ public class DefaultHeaderChannelRegistry extends IntegrationObjectSupport
this.removeOnGet = removeOnGet;
}
@Override
public void setTaskScheduler(TaskScheduler taskScheduler) {
super.setTaskScheduler(taskScheduler);
}
@Override
public final int size() {
return this.channels.size();
@@ -157,16 +151,18 @@ public class DefaultHeaderChannelRegistry extends IntegrationObjectSupport
}
@Override
@Nullable
public Object channelToChannelName(@Nullable Object channel) {
return channelToChannelName(channel, this.reaperDelay);
}
@Override
@Nullable
public Object channelToChannelName(@Nullable Object channel, long timeToLive) {
if (!this.running && !this.explicitlyStopped && this.getTaskScheduler() != null) {
start();
}
if (channel != null && channel instanceof MessageChannel) {
if (channel instanceof MessageChannel) {
String name = this.uuid + id.incrementAndGet();
this.channels.put(name, new MessageChannelWrapper((MessageChannel) channel,
System.currentTimeMillis() + timeToLive));
@@ -181,6 +177,7 @@ public class DefaultHeaderChannelRegistry extends IntegrationObjectSupport
}
@Override
@Nullable
public MessageChannel channelNameToChannel(@Nullable String name) {
if (name != null) {
MessageChannelWrapper messageChannelWrapper;

View File

@@ -205,6 +205,20 @@ public abstract class IntegrationObjectSupport implements BeanNameAware, NamedCo
return this.beanFactory;
}
/**
* Configure a {@link TaskScheduler} for those components which logic relies
* on the scheduled tasks.
* If not provided, falls back to the global {@code taskScheduler} bean
* in the application context, provided by the Spring Integration infrastructure.
* @param taskScheduler the {@link TaskScheduler} to use.
* @since 5.1.3
* @see #getTaskScheduler()
*/
public void setTaskScheduler(TaskScheduler taskScheduler) {
Assert.notNull(taskScheduler, "taskScheduler must not be null");
this.taskScheduler = taskScheduler;
}
protected TaskScheduler getTaskScheduler() {
if (this.taskScheduler == null && this.beanFactory != null) {
this.taskScheduler = IntegrationContextUtils.getTaskScheduler(this.beanFactory);
@@ -219,11 +233,6 @@ public abstract class IntegrationObjectSupport implements BeanNameAware, NamedCo
return this.channelResolver;
}
protected void setTaskScheduler(TaskScheduler taskScheduler) {
Assert.notNull(taskScheduler, "taskScheduler must not be null");
this.taskScheduler = taskScheduler;
}
public ConversionService getConversionService() {
if (this.conversionService == null && this.beanFactory != null) {
this.conversionService = IntegrationUtils.getConversionService(this.beanFactory);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
@@ -26,7 +26,6 @@ import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.integration.context.IntegrationObjectSupport;
import org.springframework.integration.context.IntegrationProperties;
import org.springframework.integration.support.SmartLifecycleRoleController;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.util.PatternMatchUtils;
import org.springframework.util.StringUtils;
@@ -56,9 +55,9 @@ public abstract class AbstractEndpoint extends IntegrationObjectSupport
private volatile boolean running;
protected final ReentrantLock lifecycleLock = new ReentrantLock();
protected final ReentrantLock lifecycleLock = new ReentrantLock(); // NOSONAR
protected final Condition lifecycleCondition = this.lifecycleLock.newCondition();
protected final Condition lifecycleCondition = this.lifecycleLock.newCondition(); // NOSONAR
private String role;
@@ -89,11 +88,6 @@ public abstract class AbstractEndpoint extends IntegrationObjectSupport
return this.role;
}
@Override
public void setTaskScheduler(TaskScheduler taskScheduler) {
super.setTaskScheduler(taskScheduler);
}
@Override
protected void onInit() {
super.onInit();
@@ -125,7 +119,7 @@ public abstract class AbstractEndpoint extends IntegrationObjectSupport
}
@Override
public void destroy() throws Exception {
public void destroy() throws Exception { // NOSONAR TODO: remove throws in 5.2
if (this.roleController != null) {
this.roleController.removeLifecycle(this);
}

View File

@@ -48,6 +48,7 @@ import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessageHandlingException;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.core.DestinationResolver;
import org.springframework.messaging.support.ErrorMessage;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.util.Assert;
@@ -142,7 +143,7 @@ public class DelayHandler extends AbstractReplyProducingMessageHandler implement
*/
public DelayHandler(String messageGroupId, TaskScheduler taskScheduler) {
this(messageGroupId);
this.setTaskScheduler(taskScheduler);
setTaskScheduler(taskScheduler);
}
/**
@@ -272,11 +273,9 @@ public class DelayHandler extends AbstractReplyProducingMessageHandler implement
if (this.delayedMessageErrorChannel != null) {
return this.delayedMessageErrorChannel;
}
if (this.delayedMessageErrorChannelName != null) {
if (getChannelResolver() != null) {
this.delayedMessageErrorChannel = getChannelResolver()
.resolveDestination(this.delayedMessageErrorChannelName);
}
DestinationResolver<MessageChannel> channelResolver = getChannelResolver();
if (this.delayedMessageErrorChannelName != null && channelResolver != null) {
this.delayedMessageErrorChannel = channelResolver.resolveDestination(this.delayedMessageErrorChannelName);
}
return this.delayedMessageErrorChannel;
}
@@ -516,11 +515,9 @@ public class DelayHandler extends AbstractReplyProducingMessageHandler implement
}
handleMessageInternal(message);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("No message in the Message Store to release: " + message +
". Likely another instance has already released it.");
}
else if (logger.isDebugEnabled()) {
logger.debug("No message in the Message Store to release: " + message +
". Likely another instance has already released it.");
}
}

View File

@@ -341,15 +341,6 @@ public class FileWritingMessageHandler extends AbstractReplyProducingMessageHand
this.flushWhenIdle = flushWhenIdle;
}
/**
* Configure a {@link TaskScheduler} for flush operations.
* @param taskScheduler the {@link TaskScheduler} to use.
*/
@Override
public void setTaskScheduler(TaskScheduler taskScheduler) { // NOSONAR
super.setTaskScheduler(taskScheduler);
}
/**
* Set a {@link MessageFlushPredicate} to use when flushing files when
* {@link FileExistsMode#APPEND_NO_FLUSH} is being used.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
@@ -35,7 +35,6 @@ import org.springframework.integration.ip.tcp.connection.TcpConnectionFailedCorr
import org.springframework.integration.ip.tcp.connection.TcpSender;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandlingException;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.util.Assert;
/**
@@ -43,35 +42,43 @@ import org.springframework.util.Assert;
* send data - if the connection factory is a server
* factory, the TcpListener owns the connections. If it is
* a client factory, this object owns the connection.
*
* @author Gary Russell
* @author Artem Bilan
*
* @since 2.0
*
*/
public class TcpSendingMessageHandler extends AbstractMessageHandler implements
TcpSender, Lifecycle, ClientModeCapable {
private volatile AbstractConnectionFactory clientConnectionFactory;
/**
* A default retry interval for the {@link ClientModeConnectionManager} rescheduling.
*/
public static final long DEFAULT_RETRY_INTERVAL = 60000;
private volatile AbstractConnectionFactory serverConnectionFactory;
protected final Object lifecycleMonitor = new Object(); // NOSONAR
private final Map<String, TcpConnection> connections = new ConcurrentHashMap<String, TcpConnection>();
private final Map<String, TcpConnection> connections = new ConcurrentHashMap<>();
private volatile boolean isClientMode;
private AbstractConnectionFactory clientConnectionFactory;
private volatile boolean isSingleUse;
private AbstractConnectionFactory serverConnectionFactory;
private volatile long retryInterval = 60000;
private boolean isClientMode;
private boolean isSingleUse;
private long retryInterval = DEFAULT_RETRY_INTERVAL;
private volatile ScheduledFuture<?> scheduledFuture;
private volatile ClientModeConnectionManager clientModeConnectionManager;
protected final Object lifecycleMonitor = new Object();
private volatile boolean active;
protected TcpConnection obtainConnection(Message<?> message) {
TcpConnection connection = null;
TcpConnection connection;
Assert.notNull(this.clientConnectionFactory, "'clientConnectionFactory' cannot be null");
try {
connection = this.clientConnectionFactory.getConnection();
@@ -89,71 +96,83 @@ public class TcpSendingMessageHandler extends AbstractMessageHandler implements
* @see org.springframework.messaging.MessageHandler#handleMessage(org.springframework.messaging.Message)
*/
@Override
public void handleMessageInternal(final Message<?> message) throws
MessageHandlingException {
public void handleMessageInternal(final Message<?> message) {
if (this.serverConnectionFactory != null) {
// We don't own the connection, we are asynchronously replying
Object connectionId = message.getHeaders().get(IpHeaders.CONNECTION_ID);
TcpConnection connection = null;
if (connectionId != null) {
connection = this.connections.get(connectionId);
}
if (connection != null) {
try {
connection.send(message);
}
catch (Exception e) {
logger.error("Error sending message", e);
connection.close();
if (e instanceof MessageHandlingException) {
throw (MessageHandlingException) e;
}
else {
throw new MessageHandlingException(message, "Error sending message", e);
}
}
finally {
if (this.isSingleUse) { // close after replying
connection.close();
}
}
}
else {
logger.error("Unable to find outbound socket for " + message);
MessageHandlingException messageHandlingException = new MessageHandlingException(message,
"Unable to find outbound socket");
publishNoConnectionEvent(messageHandlingException, (String) connectionId);
throw messageHandlingException;
}
return;
handleMessageAsServer(message);
}
else {
// we own the connection
TcpConnection connection = null;
handleMessageAsClient(message);
}
}
private void handleMessageAsServer(Message<?> message) {
// We don't own the connection, we are asynchronously replying
String connectionId = message.getHeaders().get(IpHeaders.CONNECTION_ID, String.class);
TcpConnection connection = null;
if (connectionId != null) {
connection = this.connections.get(connectionId);
}
if (connection != null) {
try {
connection = doWrite(message);
connection.send(message);
}
catch (MessageHandlingException e) {
// retry - socket may have closed
if (e.getCause() instanceof IOException) {
if (logger.isDebugEnabled()) {
logger.debug("Fail on first write attempt", e);
}
connection = doWrite(message);
}
else {
throw e;
}
catch (Exception ex) {
logger.error("Error sending message", ex);
connection.close();
throw wrapToMessageHandlingExceptionIfNecessary(message, "Error sending message", ex);
}
finally {
if (connection != null && this.isSingleUse
&& this.clientConnectionFactory.getListener() == null) {
// if there's no collaborating inbound adapter, close immediately, otherwise
// it will close after receiving the reply.
if (this.isSingleUse) { // close after replying
connection.close();
}
}
}
else {
logger.error("Unable to find outbound socket for " + message);
MessageHandlingException messageHandlingException =
new MessageHandlingException(message, "Unable to find outbound socket");
publishNoConnectionEvent(messageHandlingException, connectionId);
throw messageHandlingException;
}
}
private MessageHandlingException wrapToMessageHandlingExceptionIfNecessary(Message<?> message, String description,
Throwable cause) {
if (cause instanceof MessageHandlingException) {
throw (MessageHandlingException) cause;
}
else {
throw new MessageHandlingException(message, description, cause);
}
}
private void handleMessageAsClient(Message<?> message) {
// we own the connection
TcpConnection connection = null;
try {
connection = doWrite(message);
}
catch (MessageHandlingException e) {
// retry - socket may have closed
if (e.getCause() instanceof IOException) {
if (logger.isDebugEnabled()) {
logger.debug("Fail on first write attempt", e);
}
connection = doWrite(message);
}
else {
throw e;
}
}
finally {
if (connection != null && this.isSingleUse
&& this.clientConnectionFactory.getListener() == null) {
// if there's no collaborating inbound adapter, close immediately, otherwise
// it will close after receiving the reply.
connection.close();
}
}
}
/**
@@ -170,15 +189,13 @@ public class TcpSendingMessageHandler extends AbstractMessageHandler implements
}
connection.send(message);
}
catch (Exception e) {
catch (Exception ex) {
String connectionId = null;
if (connection != null) {
connectionId = connection.getConnectionId();
}
if (e instanceof MessageHandlingException) {
throw (MessageHandlingException) e;
}
throw new MessageHandlingException(message, "Failed to handle message using " + connectionId, e);
throw wrapToMessageHandlingExceptionIfNecessary(message,
"Failed to handle message using " + connectionId, ex);
}
return connection;
}
@@ -189,7 +206,7 @@ public class TcpSendingMessageHandler extends AbstractMessageHandler implements
ApplicationEventPublisher applicationEventPublisher = cf.getApplicationEventPublisher();
if (applicationEventPublisher != null) {
applicationEventPublisher.publishEvent(
new TcpConnectionFailedCorrelationEvent(this, connectionId, messageHandlingException));
new TcpConnectionFailedCorrelationEvent(this, connectionId, messageHandlingException));
}
}
@@ -230,8 +247,7 @@ public class TcpSendingMessageHandler extends AbstractMessageHandler implements
protected void onInit() {
super.onInit();
if (this.isClientMode) {
Assert.notNull(this.clientConnectionFactory,
"For client-mode, connection factory must be type='client'");
Assert.notNull(this.clientConnectionFactory, "For client-mode, connection factory must be type='client'");
Assert.isTrue(!this.clientConnectionFactory.isSingleUse(),
"For client-mode, connection factory must have single-use='false'");
}
@@ -249,11 +265,13 @@ public class TcpSendingMessageHandler extends AbstractMessageHandler implements
this.serverConnectionFactory.start();
}
if (this.isClientMode) {
ClientModeConnectionManager manager = new ClientModeConnectionManager(
this.clientConnectionFactory);
Assert.notNull(this.clientConnectionFactory,
"For client-mode, connection factory must be type='client'");
ClientModeConnectionManager manager =
new ClientModeConnectionManager(this.clientConnectionFactory);
this.clientModeConnectionManager = manager;
Assert.state(this.getTaskScheduler() != null, "Client mode requires a task scheduler");
this.scheduledFuture = this.getTaskScheduler().scheduleAtFixedRate(manager, this.retryInterval);
Assert.state(getTaskScheduler() != null, "Client mode requires a task scheduler");
this.scheduledFuture = getTaskScheduler().scheduleAtFixedRate(manager, this.retryInterval);
}
}
}
@@ -319,11 +337,6 @@ public class TcpSendingMessageHandler extends AbstractMessageHandler implements
this.isClientMode = isClientMode;
}
@Override // super class is protected
public void setTaskScheduler(TaskScheduler taskScheduler) {
super.setTaskScheduler(taskScheduler);
}
/**
* @return the retryInterval
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2018 the original author or authors.
* Copyright 2016-2019 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.
@@ -99,9 +99,14 @@ public class JmsInboundGateway extends MessagingGatewaySupport implements Dispos
}
@Override
public void destroy() throws Exception {
public void destroy() {
this.endpoint.destroy();
super.destroy();
try {
super.destroy();
}
catch (Exception e) {
throw new IllegalStateException(e);
}
}
@Override

View File

@@ -36,7 +36,8 @@ import org.springframework.util.Assert;
* @author Gary Russell
* @author Artem Bilan
*/
public class JmsMessageDrivenEndpoint extends MessageProducerSupport implements DisposableBean, OrderlyShutdownCapable {
public class JmsMessageDrivenEndpoint extends MessageProducerSupport
implements DisposableBean, OrderlyShutdownCapable {
private final AbstractMessageListenerContainer listenerContainer;
@@ -73,7 +74,7 @@ public class JmsMessageDrivenEndpoint extends MessageProducerSupport implements
ChannelPublishingJmsMessageListener listener, boolean externalContainer) {
Assert.notNull(listenerContainer, "listener container must not be null");
Assert.notNull(listener, "listener must not be null");
if (logger.isWarnEnabled() && listenerContainer.getMessageListener() != null) {
if (listenerContainer.getMessageListener() != null) {
logger.warn("The provided listener container already has a MessageListener implementation, " +
"but it will be overridden by the provided ChannelPublishingJmsMessageListener.");
}
@@ -212,12 +213,17 @@ public class JmsMessageDrivenEndpoint extends MessageProducerSupport implements
}
@Override
public void destroy() throws Exception {
public void destroy() {
if (this.isRunning()) {
this.stop();
}
this.listenerContainer.destroy();
super.destroy();
try {
super.destroy();
}
catch (Exception e) {
throw new IllegalStateException(e);
}
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
@@ -138,9 +138,14 @@ public class RmiInboundGateway extends MessagingGatewaySupport
}
@Override
public void destroy() throws Exception {
super.destroy();
this.exporter.destroy();
public void destroy() {
try {
super.destroy();
this.exporter.destroy();
}
catch (Exception e) {
throw new IllegalStateException(e);
}
}
}