/*
* Copyright 2002-2016 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.config;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.SmartLifecycle;
import org.springframework.integration.core.MessageSource;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.scheduling.PollerMetadata;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.core.BeanFactoryMessageChannelDestinationResolver;
import org.springframework.messaging.core.DestinationResolver;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* FactoryBean for creating a SourcePollingChannelAdapter instance.
*
* @author Mark Fisher
* @author Oleg Zhurakousky
* @author Gary Russell
* @author Artem Bilan
*/
public class SourcePollingChannelAdapterFactoryBean implements FactoryBean<SourcePollingChannelAdapter>,
BeanFactoryAware, BeanNameAware, BeanClassLoaderAware, InitializingBean, SmartLifecycle {
private volatile MessageSource<?> source;
private volatile MessageChannel outputChannel;
private volatile String outputChannelName;
private volatile PollerMetadata pollerMetadata;
private volatile boolean autoStartup = true;
private volatile int phase = Integer.MAX_VALUE / 2;
private volatile Long sendTimeout;
private volatile String beanName;
private volatile ConfigurableBeanFactory beanFactory;
private volatile ClassLoader beanClassLoader;
private volatile SourcePollingChannelAdapter adapter;
private volatile boolean initialized;
private volatile DestinationResolver<MessageChannel> channelResolver;
private final Object initializationMonitor = new Object();
public void setSource(MessageSource<?> source) {
this.source = source;
}
public void setSendTimeout(long sendTimeout) {
this.sendTimeout = sendTimeout;
}
public void setOutputChannel(MessageChannel outputChannel) {
this.outputChannel = outputChannel;
}
public void setOutputChannelName(String outputChannelName) {
this.outputChannelName = outputChannelName;
}
public void setPollerMetadata(PollerMetadata pollerMetadata) {
this.pollerMetadata = pollerMetadata;
}
public void setAutoStartup(boolean autoStartup) {
this.autoStartup = autoStartup;
}
public void setPhase(int phase) {
this.phase = phase;
}
/**
* Specify the {@link DestinationResolver} strategy to use.
* The default is a BeanFactoryChannelResolver.
* @param channelResolver The channel resolver.
* @since 4.1.3
*/
public void setChannelResolver(DestinationResolver<MessageChannel> channelResolver) {
Assert.notNull(channelResolver, "'channelResolver' must not be null");
this.channelResolver = channelResolver;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
Assert.isInstanceOf(ConfigurableBeanFactory.class, beanFactory,
"a ConfigurableBeanFactory is required");
this.beanFactory = (ConfigurableBeanFactory) beanFactory;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
@Override
public void setBeanName(String beanName) {
this.beanName = beanName;
}
@Override
public void afterPropertiesSet() throws Exception {
if (this.channelResolver == null) {
this.channelResolver = new BeanFactoryMessageChannelDestinationResolver(this.beanFactory);
}
initializeAdapter();
}
@Override
public SourcePollingChannelAdapter getObject() throws Exception {
if (this.adapter == null) {
initializeAdapter();
}
return this.adapter;
}
@Override
public Class<?> getObjectType() {
return SourcePollingChannelAdapter.class;
}
@Override
public boolean isSingleton() {
return true;
}
private void initializeAdapter() {
synchronized (this.initializationMonitor) {
if (this.initialized) {
return;
}
Assert.notNull(this.source, "source is required");
if (StringUtils.hasText(this.outputChannelName)) {
Assert.isNull(this.outputChannel, "'outputChannelName' and 'outputChannel' are mutually exclusive.");
this.outputChannel = this.channelResolver.resolveDestination(this.outputChannelName);
}
Assert.notNull(this.outputChannel, "outputChannel is required");
SourcePollingChannelAdapter spca = new SourcePollingChannelAdapter();
spca.setSource(this.source);
spca.setOutputChannel(this.outputChannel);
if (this.pollerMetadata == null) {
this.pollerMetadata = PollerMetadata.getDefaultPollerMetadata(this.beanFactory);
Assert.notNull(this.pollerMetadata, "No poller has been defined for channel-adapter '"
+ this.beanName + "', and no default poller is available within the context.");
}
if (this.pollerMetadata.getMaxMessagesPerPoll() == Integer.MIN_VALUE) {
// the default is 1 since a source might return
// a non-null and non-interruptible value every time it is invoked
this.pollerMetadata.setMaxMessagesPerPoll(1);
}
spca.setMaxMessagesPerPoll(this.pollerMetadata.getMaxMessagesPerPoll());
if (this.sendTimeout != null) {
spca.setSendTimeout(this.sendTimeout);
}
spca.setTaskExecutor(this.pollerMetadata.getTaskExecutor());
spca.setAdviceChain(this.pollerMetadata.getAdviceChain());
spca.setTrigger(this.pollerMetadata.getTrigger());
spca.setErrorHandler(this.pollerMetadata.getErrorHandler());
spca.setBeanClassLoader(this.beanClassLoader);
spca.setAutoStartup(this.autoStartup);
spca.setPhase(this.phase);
spca.setBeanName(this.beanName);
spca.setBeanFactory(this.beanFactory);
spca.setTransactionSynchronizationFactory(this.pollerMetadata.getTransactionSynchronizationFactory());
spca.afterPropertiesSet();
this.adapter = spca;
this.initialized = true;
}
}
/*
* SmartLifecycle implementation (delegates to the created adapter)
*/
@Override
public boolean isAutoStartup() {
return (this.adapter == null) || this.adapter.isAutoStartup();
}
@Override
public int getPhase() {
return (this.adapter != null) ? this.adapter.getPhase() : 0;
}
@Override
public boolean isRunning() {
return (this.adapter != null) && this.adapter.isRunning();
}
@Override
public void start() {
if (this.adapter != null) {
this.adapter.start();
}
}
@Override
public void stop() {
if (this.adapter != null) {
this.adapter.stop();
}
}
@Override
public void stop(Runnable callback) {
if (this.adapter != null) {
this.adapter.stop(callback);
}
}
}