INT-4491: (S)FTP inbound rotate dirs/servers
JIRA: https://jira.spring.io/browse/INT-4491 Add Rotating Server/Directory Polling Advice. **cherry-pick to 5.0.x** * Polishing - PR Comments. * Polishing * Polishing; revert `KeyDirectory`; WARN about `TaskExecutor` and `MessageSoureMutator`(s). * More polishing - PR comments * Apply stashed changes. * Fix WARN log - the `SyncTaskExecutor` is wrapped. # Conflicts: # spring-integration-core/src/main/java/org/springframework/integration/endpoint/SourcePollingChannelAdapter.java # src/reference/asciidoc/whats-new.adoc
This commit is contained in:
committed by
Artem Bilan
parent
170cc37270
commit
9f937f54cd
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,9 +27,10 @@ import org.springframework.messaging.Message;
|
||||
* should be ignored and/or take action after the receive.
|
||||
*
|
||||
* @author Gary Russell
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
public abstract class AbstractMessageSourceAdvice implements MethodInterceptor {
|
||||
public abstract class AbstractMessageSourceAdvice implements MethodInterceptor, MessageSourceMutator {
|
||||
|
||||
@Override
|
||||
public final Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
@@ -45,20 +46,4 @@ public abstract class AbstractMessageSourceAdvice implements MethodInterceptor {
|
||||
return afterReceive(result, (MessageSource<?>) target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses can decide whether to proceed with this poll.
|
||||
* @param source the message source.
|
||||
* @return true to proceed.
|
||||
*/
|
||||
public abstract boolean beforeReceive(MessageSource<?> source);
|
||||
|
||||
/**
|
||||
* Subclasses can take actions based on the result of the poll; e.g.
|
||||
* adjust the {@code trigger}. The message can also be replaced with a new one.
|
||||
* @param result the received message.
|
||||
* @param source the message source.
|
||||
* @return a message to continue to process the result, null to discard whatever the poll returned.
|
||||
*/
|
||||
public abstract Message<?> afterReceive(Message<?> result, MessageSource<?> source);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015-2016 the original author or authors.
|
||||
* Copyright 2015-2018 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.
|
||||
@@ -47,11 +47,6 @@ public class CompoundTriggerAdvice extends AbstractMessageSourceAdvice {
|
||||
this.override = overrideTrigger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean beforeReceive(MessageSource<?> source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message<?> afterReceive(Message<?> result, MessageSource<?> source) {
|
||||
if (result == null) {
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2018 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
|
||||
*
|
||||
* http://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.aop;
|
||||
|
||||
import org.springframework.integration.core.MessageSource;
|
||||
import org.springframework.messaging.Message;
|
||||
|
||||
/**
|
||||
* An object that can mutate a {@link MessageSource} before and/or after
|
||||
* {@link MessageSource#receive()} is called.
|
||||
*
|
||||
* @author Gary Russell
|
||||
*
|
||||
* @since 5.0.7.
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface MessageSourceMutator {
|
||||
|
||||
/**
|
||||
* Subclasses can decide whether to proceed with this poll.
|
||||
* @param source the message source.
|
||||
* @return true to proceed (default).
|
||||
*/
|
||||
default boolean beforeReceive(MessageSource<?> source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses can take actions based on the result of the poll; e.g.
|
||||
* adjust the {@code trigger}. The message can also be replaced with a new one.
|
||||
* @param result the received message.
|
||||
* @param source the message source.
|
||||
* @return a message to continue to process the result, null to discard whatever the poll returned.
|
||||
*/
|
||||
Message<?> afterReceive(Message<?> result, MessageSource<?> source);
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* Copyright 2015-2018 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.
|
||||
@@ -61,11 +61,6 @@ public class SimpleActiveIdleMessageSourceAdvice extends AbstractMessageSourceAd
|
||||
this.activePollPeriod = activePollPeriod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean beforeReceive(MessageSource<?> source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message<?> afterReceive(Message<?> result, MessageSource<?> source) {
|
||||
if (result == null) {
|
||||
|
||||
@@ -75,7 +75,7 @@ public final class PollerSpec extends IntegrationComponentSpec<PollerSpec, Polle
|
||||
* to the {@link org.springframework.integration.util.ErrorHandlingTaskExecutor}.
|
||||
* @param errorHandler the {@link ErrorHandler} to use.
|
||||
* @return the spec.
|
||||
* @see #taskExecutor
|
||||
* @see #taskExecutor(Executor)
|
||||
*/
|
||||
public PollerSpec errorHandler(ErrorHandler errorHandler) {
|
||||
this.target.setErrorHandler(errorHandler);
|
||||
|
||||
@@ -60,17 +60,25 @@ import org.springframework.util.ErrorHandler;
|
||||
*/
|
||||
public abstract class AbstractPollingEndpoint extends AbstractEndpoint implements BeanClassLoaderAware {
|
||||
|
||||
private volatile Executor taskExecutor = new SyncTaskExecutor();
|
||||
private final Object initializationMonitor = new Object();
|
||||
|
||||
private volatile ErrorHandler errorHandler;
|
||||
private Executor taskExecutor = new SyncTaskExecutor();
|
||||
|
||||
private volatile boolean errorHandlerIsDefault;
|
||||
private boolean syncExecutor = true;
|
||||
|
||||
private volatile Trigger trigger = new PeriodicTrigger(10);
|
||||
private ErrorHandler errorHandler;
|
||||
|
||||
private volatile List<Advice> adviceChain;
|
||||
private boolean errorHandlerIsDefault;
|
||||
|
||||
private volatile ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
private Trigger trigger = new PeriodicTrigger(10);
|
||||
|
||||
private List<Advice> adviceChain;
|
||||
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
|
||||
private long maxMessagesPerPoll = -1;
|
||||
|
||||
private TransactionSynchronizationFactory transactionSynchronizationFactory;
|
||||
|
||||
private volatile ScheduledFuture<?> runningTask;
|
||||
|
||||
@@ -78,18 +86,23 @@ public abstract class AbstractPollingEndpoint extends AbstractEndpoint implement
|
||||
|
||||
private volatile boolean initialized;
|
||||
|
||||
private volatile long maxMessagesPerPoll = -1;
|
||||
|
||||
private final Object initializationMonitor = new Object();
|
||||
|
||||
private volatile TransactionSynchronizationFactory transactionSynchronizationFactory;
|
||||
|
||||
public AbstractPollingEndpoint() {
|
||||
this.setPhase(Integer.MAX_VALUE / 2);
|
||||
}
|
||||
|
||||
public void setTaskExecutor(Executor taskExecutor) {
|
||||
this.taskExecutor = (taskExecutor != null ? taskExecutor : new SyncTaskExecutor());
|
||||
this.syncExecutor = this.taskExecutor instanceof SyncTaskExecutor
|
||||
|| (this.taskExecutor instanceof ErrorHandlingTaskExecutor
|
||||
&& ((ErrorHandlingTaskExecutor) this.taskExecutor).isSyncExecutor());
|
||||
}
|
||||
|
||||
protected Executor getTaskExecutor() {
|
||||
return this.taskExecutor;
|
||||
}
|
||||
|
||||
protected boolean isSyncExecutor() {
|
||||
return this.syncExecutor;
|
||||
}
|
||||
|
||||
public void setTrigger(Trigger trigger) {
|
||||
|
||||
@@ -27,7 +27,7 @@ import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.aop.support.NameMatchMethodPointcutAdvisor;
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.context.Lifecycle;
|
||||
import org.springframework.integration.aop.AbstractMessageSourceAdvice;
|
||||
import org.springframework.integration.aop.MessageSourceMutator;
|
||||
import org.springframework.integration.context.ExpressionCapable;
|
||||
import org.springframework.integration.core.MessageSource;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
@@ -137,7 +137,7 @@ public class SourcePollingChannelAdapter extends AbstractPollingEndpoint
|
||||
|
||||
@Override
|
||||
protected boolean isReceiveOnlyAdvice(Advice advice) {
|
||||
return advice instanceof AbstractMessageSourceAdvice;
|
||||
return advice instanceof MessageSourceMutator;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -159,6 +159,13 @@ public class SourcePollingChannelAdapter extends AbstractPollingEndpoint
|
||||
}
|
||||
this.appliedAdvices.clear();
|
||||
this.appliedAdvices.addAll(chain);
|
||||
if (!(isSyncExecutor()) && logger.isWarnEnabled()) {
|
||||
logger.warn(getComponentName() + ": A task executor is supplied and " + chain.size()
|
||||
+ "MessageSourceMutator(s) is/are provided. If an advice mutates the source, such "
|
||||
+ "mutations are not thread safe and could cause unexpected results, especially with "
|
||||
+ "high frequency pollers. Consider using a downstream ExecutorChannel instead of "
|
||||
+ "adding an executor to the poller");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.integration.util;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ErrorHandler;
|
||||
@@ -45,6 +46,9 @@ public class ErrorHandlingTaskExecutor implements TaskExecutor {
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
public boolean isSyncExecutor() {
|
||||
return this.executor instanceof SyncTaskExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(final Runnable task) {
|
||||
|
||||
Reference in New Issue
Block a user