Channel Adapters are now endpoints, but if no "channel" attribute if provided for a <channel-adapter/> element, a DirectChannel will be created automatically. The <poller/> sub-element now belongs within the <channel-adapter/> (not the consumer endpoint downstream). This enables support for multiple Channel Adapters to share a MessageChannel. Also, the @Poller annotation belongs at class-level along with @ChannelAdapter if a @Pollable method is being adapted via MethodInvokingSource.
This commit is contained in:
@@ -39,7 +39,7 @@ import org.springframework.integration.scheduling.PollingSchedule;
|
||||
@Documented
|
||||
public @interface Poller {
|
||||
|
||||
int period() default 0;
|
||||
int period();
|
||||
|
||||
long initialDelay() default PollingSchedule.DEFAULT_INITIAL_DELAY;
|
||||
|
||||
@@ -47,6 +47,6 @@ public @interface Poller {
|
||||
|
||||
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
|
||||
|
||||
int maxMessagesPerPoll() default 1;
|
||||
int maxMessagesPerPoll() default -1;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.channel;
|
||||
|
||||
import org.springframework.integration.message.BlockingTarget;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageTarget;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The base class for Channel Adapters.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class AbstractChannelAdapter extends AbstractMessageChannel {
|
||||
|
||||
private final MessageTarget target;
|
||||
|
||||
|
||||
public AbstractChannelAdapter(String name, MessageTarget target) {
|
||||
Assert.notNull(name, "name must not be null");
|
||||
this.setBeanName(name);
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean doSend(Message<?> message, long timeout) {
|
||||
if (this.target == null) {
|
||||
return false;
|
||||
}
|
||||
return (timeout >= 0 && this.target instanceof BlockingTarget)
|
||||
? ((BlockingTarget) this.target).send(message, timeout)
|
||||
: this.target.send(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.channel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.integration.message.BlockingSource;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageDeliveryAware;
|
||||
import org.springframework.integration.message.MessageTarget;
|
||||
import org.springframework.integration.message.MessagingException;
|
||||
import org.springframework.integration.message.PollableSource;
|
||||
import org.springframework.integration.message.selector.MessageSelector;
|
||||
|
||||
/**
|
||||
* Channel Adapter implementation for a {@link PollableSource}.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class PollableChannelAdapter extends AbstractChannelAdapter implements PollableChannel, MessageDeliveryAware {
|
||||
|
||||
private final PollableSource<?> source;
|
||||
|
||||
|
||||
public PollableChannelAdapter(String name, PollableSource<?> source, MessageTarget target) {
|
||||
super(name, target);
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
|
||||
public Message<?> receive() {
|
||||
return this.receive(-1);
|
||||
}
|
||||
|
||||
public Message<?> receive(long timeout) {
|
||||
if (this.source != null) {
|
||||
return (timeout >= 0 && this.source instanceof BlockingSource)
|
||||
? ((BlockingSource<?>) this.source).receive(timeout)
|
||||
: this.source.receive();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Message<?>> clear() {
|
||||
if (this.source != null && this.source instanceof PollableChannel) {
|
||||
return ((PollableChannel) this.source).clear();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Message<?>> purge(MessageSelector selector) {
|
||||
if (this.source != null && this.source instanceof PollableChannel) {
|
||||
return ((PollableChannel) this.source).purge(selector);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void onSend(Message<?> sentMessage) {
|
||||
if (this.source != null && this.source instanceof MessageDeliveryAware) {
|
||||
((MessageDeliveryAware) this.source).onSend(sentMessage);
|
||||
}
|
||||
}
|
||||
|
||||
public void onFailure(MessagingException exception) {
|
||||
if (this.source != null && this.source instanceof MessageDeliveryAware) {
|
||||
((MessageDeliveryAware) this.source).onFailure(exception);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.channel;
|
||||
|
||||
import org.springframework.integration.message.MessageTarget;
|
||||
import org.springframework.integration.message.SubscribableSource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Channel Adapter implementation for a {@link SubscribableSource}.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class SubscribableChannelAdapter extends AbstractChannelAdapter implements SubscribableSource {
|
||||
|
||||
private final SubscribableSource source;
|
||||
|
||||
|
||||
public SubscribableChannelAdapter(String name, SubscribableSource source, MessageTarget target) {
|
||||
super(name, target);
|
||||
Assert.notNull(source, "source must not be null");
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
|
||||
public boolean subscribe(MessageTarget target) {
|
||||
return this.source.subscribe(target);
|
||||
}
|
||||
|
||||
public boolean unsubscribe(MessageTarget target) {
|
||||
return this.source.unsubscribe(target);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.channel.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.channel.AbstractMessageChannel;
|
||||
import org.springframework.integration.channel.ChannelInterceptor;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.channel.PollableChannelAdapter;
|
||||
import org.springframework.integration.channel.SubscribableChannelAdapter;
|
||||
import org.springframework.integration.message.MessageSource;
|
||||
import org.springframework.integration.message.MessageTarget;
|
||||
import org.springframework.integration.message.PollableSource;
|
||||
import org.springframework.integration.message.SubscribableSource;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class ChannelAdapterFactoryBean implements FactoryBean, BeanNameAware {
|
||||
|
||||
private volatile String name;
|
||||
|
||||
private volatile MessageSource<?> source;
|
||||
|
||||
private volatile MessageTarget target;
|
||||
|
||||
private volatile AbstractMessageChannel channel;
|
||||
|
||||
private List<ChannelInterceptor> interceptors;
|
||||
|
||||
private volatile boolean initialized;
|
||||
|
||||
private final Object initializationMonitor = new Object();
|
||||
|
||||
|
||||
public void setBeanName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setSource(MessageSource<?> source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public void setTarget(MessageTarget target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public void setInterceptors(List<ChannelInterceptor> interceptors) {
|
||||
this.interceptors = interceptors;
|
||||
}
|
||||
|
||||
public Object getObject() throws Exception {
|
||||
if (!this.initialized) {
|
||||
this.initializeChannel();
|
||||
}
|
||||
return this.channel;
|
||||
}
|
||||
|
||||
public Class<?> getObjectType() {
|
||||
if (!this.initialized) {
|
||||
return MessageChannel.class;
|
||||
}
|
||||
return this.channel.getClass();
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void initializeChannel() {
|
||||
synchronized (this.initializationMonitor) {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
if (this.source == null || source instanceof PollableSource) {
|
||||
this.channel = new PollableChannelAdapter(
|
||||
this.name, (PollableSource<?>) this.source, this.target);
|
||||
}
|
||||
else if (this.source instanceof SubscribableSource) {
|
||||
this.channel = new SubscribableChannelAdapter(
|
||||
this.name, (SubscribableSource) this.source, this.target);
|
||||
}
|
||||
else {
|
||||
throw new ConfigurationException("source must be either a PollableSource or SubscribableSource");
|
||||
}
|
||||
if (this.interceptors != null) {
|
||||
this.channel.setInterceptors(this.interceptors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,24 +18,98 @@ package org.springframework.integration.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.integration.channel.config.ChannelAdapterFactoryBean;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.endpoint.InboundChannelAdapter;
|
||||
import org.springframework.integration.endpoint.OutboundChannelAdapter;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
|
||||
/**
|
||||
* Parser for the <channel-adapter/> element.
|
||||
* Parser for the <channel-adapter/> element.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class ChannelAdapterParser extends AbstractChannelParser {
|
||||
public class ChannelAdapterParser extends AbstractBeanDefinitionParser {
|
||||
|
||||
protected final Class<?> getBeanClass(Element element) {
|
||||
return ChannelAdapterFactoryBean.class;
|
||||
@Override
|
||||
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException {
|
||||
String id = element.getAttribute("id");
|
||||
if (!element.hasAttribute("channel")) {
|
||||
// the created channel will get the 'id', so the adapter's bean name includes a suffix
|
||||
id = id + ".adapter";
|
||||
}
|
||||
else if (!StringUtils.hasText(id)) {
|
||||
id = parserContext.getReaderContext().generateBeanName(definition);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postProcess(BeanDefinitionBuilder builder, Element element) {
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "source");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "target");
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
String source = element.getAttribute("source");
|
||||
String target = element.getAttribute("target");
|
||||
String channelName = element.getAttribute("channel");
|
||||
Element pollerElement = DomUtils.getChildElementByTagName(element, "poller");
|
||||
BeanDefinitionBuilder adapterBuilder = null;
|
||||
if (StringUtils.hasText(source)) {
|
||||
if (StringUtils.hasText(target)) {
|
||||
throw new ConfigurationException("both 'source' and 'target' are not allowed, provide only one");
|
||||
}
|
||||
adapterBuilder = BeanDefinitionBuilder.genericBeanDefinition(InboundChannelAdapter.class);
|
||||
if (pollerElement != null) {
|
||||
String pollerBeanName = IntegrationNamespaceUtils.parsePoller(source, pollerElement, parserContext);
|
||||
adapterBuilder.addPropertyReference("source", pollerBeanName);
|
||||
}
|
||||
else {
|
||||
adapterBuilder.addPropertyReference("source", source);
|
||||
}
|
||||
if (StringUtils.hasText(channelName)) {
|
||||
adapterBuilder.addPropertyReference("target", channelName);
|
||||
}
|
||||
else {
|
||||
adapterBuilder.addPropertyReference("target",
|
||||
this.createDirectChannel(element, parserContext));
|
||||
}
|
||||
}
|
||||
else if (StringUtils.hasText(target)) {
|
||||
adapterBuilder = BeanDefinitionBuilder.genericBeanDefinition(OutboundChannelAdapter.class);
|
||||
adapterBuilder.addPropertyReference("target", target);
|
||||
if (pollerElement != null) {
|
||||
if (!StringUtils.hasText(channelName)) {
|
||||
throw new ConfigurationException("outbound channel-adapter with a 'poller' requires a 'channel' to poll");
|
||||
}
|
||||
String pollerBeanName = IntegrationNamespaceUtils.parsePoller(channelName, pollerElement, parserContext);
|
||||
adapterBuilder.addPropertyReference("source", pollerBeanName);
|
||||
}
|
||||
else {
|
||||
adapterBuilder.addPropertyReference("source",
|
||||
this.createDirectChannel(element, parserContext));
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new ConfigurationException("either 'source' or 'target' is required");
|
||||
}
|
||||
return adapterBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
private String createDirectChannel(Element element, ParserContext parserContext) {
|
||||
String channelId = element.getAttribute("id");
|
||||
if (!StringUtils.hasText(channelId)) {
|
||||
throw new ConfigurationException("The channel-adapter's 'id' attribute is required when no 'channel' "
|
||||
+ "reference has been provided, because that 'id' would be used for the created channel.");
|
||||
}
|
||||
BeanDefinitionBuilder channelBuilder = BeanDefinitionBuilder.genericBeanDefinition(DirectChannel.class);
|
||||
BeanDefinitionHolder holder = new BeanDefinitionHolder(channelBuilder.getBeanDefinition(), channelId);
|
||||
BeanDefinitionReaderUtils.registerBeanDefinition(holder, parserContext.getRegistry());
|
||||
return channelId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,12 +25,7 @@ import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.core.Conventions;
|
||||
import org.springframework.integration.dispatcher.PollingDispatcher;
|
||||
import org.springframework.integration.dispatcher.SimpleDispatcher;
|
||||
import org.springframework.integration.message.AsyncMessageExchangeTemplate;
|
||||
import org.springframework.integration.message.MessageExchangeTemplate;
|
||||
import org.springframework.integration.scheduling.PollingSchedule;
|
||||
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
|
||||
@@ -145,7 +140,7 @@ public abstract class IntegrationNamespaceUtils {
|
||||
* @return the name of the poller bean definition
|
||||
*/
|
||||
public static String parsePoller(String sourceBeanName, Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(PollingDispatcher.class);
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(PollingDispatcherFactoryBean.class);
|
||||
Long period = Long.valueOf(element.getAttribute("period"));
|
||||
PollingSchedule schedule = new PollingSchedule(period);
|
||||
String initialDelay = element.getAttribute("initial-delay");
|
||||
@@ -158,42 +153,21 @@ public abstract class IntegrationNamespaceUtils {
|
||||
else {
|
||||
schedule.setFixedRate(false);
|
||||
}
|
||||
String templateBeanName = parseMessageExhangeTemplate(element, parserContext);
|
||||
builder.addConstructorArgReference(sourceBeanName);
|
||||
builder.addConstructorArgValue(schedule);
|
||||
builder.addConstructorArgValue(new SimpleDispatcher());
|
||||
builder.addConstructorArgReference(templateBeanName);
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "task-executor");
|
||||
Element txElement = DomUtils.getChildElementByTagName(element, "transactional");
|
||||
if (txElement != null) {
|
||||
builder.addPropertyReference("transactionManager", txElement.getAttribute("transaction-manager"));
|
||||
builder.addPropertyValue("propagationBehaviorName", txElement.getAttribute("propagation"));
|
||||
builder.addPropertyValue("isolationLevelName", txElement.getAttribute("isolation"));
|
||||
builder.addPropertyValue("transactionTimeout", txElement.getAttribute("timeout"));
|
||||
builder.addPropertyValue("transactionReadOnly", txElement.getAttribute("read-only"));
|
||||
}
|
||||
builder.addPropertyReference("source", sourceBeanName);
|
||||
builder.addPropertyValue("schedule", schedule);
|
||||
setValueIfAttributeDefined(builder, element, "receive-timeout");
|
||||
setValueIfAttributeDefined(builder, element, "send-timeout");
|
||||
setValueIfAttributeDefined(builder, element, "max-messages-per-poll");
|
||||
return BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry());
|
||||
}
|
||||
|
||||
private static String parseMessageExhangeTemplate(Element element, ParserContext parserContext) {
|
||||
String taskExecutorRef = element.getAttribute("task-executor");
|
||||
Element txElement = DomUtils.getChildElementByTagName(element, "transactional");
|
||||
Class<?> beanClass = (StringUtils.hasText(taskExecutorRef)) ?
|
||||
AsyncMessageExchangeTemplate.class : MessageExchangeTemplate.class;
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClass);
|
||||
if (StringUtils.hasText(taskExecutorRef)) {
|
||||
builder.addConstructorArgReference(taskExecutorRef);
|
||||
}
|
||||
if (txElement != null) {
|
||||
builder.addPropertyReference("transactionManager", txElement.getAttribute("transaction-manager"));
|
||||
builder.addPropertyValue("propagationBehaviorName", DefaultTransactionDefinition.PREFIX_PROPAGATION + txElement.getAttribute("propagation"));
|
||||
builder.addPropertyValue("isolationLevelName", DefaultTransactionDefinition.PREFIX_ISOLATION + txElement.getAttribute("isolation"));
|
||||
builder.addPropertyValue("transactionTimeout", txElement.getAttribute("timeout"));
|
||||
builder.addPropertyValue("transactionReadOnly", txElement.getAttribute("read-only"));
|
||||
}
|
||||
String receiveTimeout = element.getAttribute("receive-timeout");
|
||||
if (StringUtils.hasText(receiveTimeout)) {
|
||||
builder.addPropertyValue("receiveTimeout", Long.parseLong(receiveTimeout));
|
||||
}
|
||||
String sendTimeout = element.getAttribute("send-timeout");
|
||||
if (StringUtils.hasText(sendTimeout)) {
|
||||
builder.addPropertyValue("sendTimeout", Long.parseLong(sendTimeout));
|
||||
}
|
||||
return BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), parserContext.getRegistry());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.BeanCreationException;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.dispatcher.PollingDispatcher;
|
||||
import org.springframework.integration.dispatcher.SimpleDispatcher;
|
||||
import org.springframework.integration.message.AsyncMessageExchangeTemplate;
|
||||
import org.springframework.integration.message.MessageExchangeTemplate;
|
||||
import org.springframework.integration.message.MessageSource;
|
||||
import org.springframework.integration.message.PollableSource;
|
||||
import org.springframework.integration.scheduling.PollingSchedule;
|
||||
import org.springframework.integration.scheduling.Schedule;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class PollingDispatcherFactoryBean implements FactoryBean, InitializingBean {
|
||||
|
||||
private volatile PollingDispatcher poller;
|
||||
|
||||
private volatile MessageSource<?> source;
|
||||
|
||||
private volatile Schedule schedule;
|
||||
|
||||
private volatile long receiveTimeout = -1;
|
||||
|
||||
private volatile long sendTimeout = -1;
|
||||
|
||||
private volatile int maxMessagesPerPoll = -1;
|
||||
|
||||
private volatile TaskExecutor taskExecutor;
|
||||
|
||||
private volatile PlatformTransactionManager transactionManager;
|
||||
|
||||
private volatile String propagationBehaviorName;
|
||||
|
||||
private volatile String isolationLevelName;
|
||||
|
||||
private volatile int transactionTimeout;
|
||||
|
||||
private volatile boolean transactionReadOnly;
|
||||
|
||||
private volatile boolean validated;
|
||||
|
||||
private volatile boolean initialized;
|
||||
|
||||
private final Object initializationMonitor = new Object();
|
||||
|
||||
|
||||
public void setSource(MessageSource<?> source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public void setSchedule(Schedule schedule) {
|
||||
this.schedule = schedule;
|
||||
}
|
||||
|
||||
public void setReceiveTimeout(long receiveTimeout) {
|
||||
this.receiveTimeout = receiveTimeout;
|
||||
}
|
||||
|
||||
public void setSendTimeout(long sendTimeout) {
|
||||
this.sendTimeout = sendTimeout;
|
||||
}
|
||||
|
||||
public void setMaxMessagesPerPoll(int maxMessagesPerPoll) {
|
||||
this.maxMessagesPerPoll = maxMessagesPerPoll;
|
||||
}
|
||||
|
||||
public void setTaskExecutor(TaskExecutor taskExecutor) {
|
||||
this.taskExecutor = taskExecutor;
|
||||
}
|
||||
|
||||
public void setTransactionManager(PlatformTransactionManager transactionManager) {
|
||||
this.transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
public void setPropagationBehaviorName(String propagationBehaviorName) {
|
||||
this.propagationBehaviorName = propagationBehaviorName;
|
||||
}
|
||||
|
||||
public void setIsolationLevelName(String isolationLevelName) {
|
||||
this.isolationLevelName = isolationLevelName;
|
||||
}
|
||||
|
||||
public void setTransactionTimeout(int transactionTimeout) {
|
||||
this.transactionTimeout = transactionTimeout;
|
||||
}
|
||||
|
||||
public void setTransactionReadOnly(boolean transactionReadOnly) {
|
||||
this.transactionReadOnly = transactionReadOnly;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
synchronized (this.initializationMonitor) {
|
||||
if (this.source == null) {
|
||||
throw new ConfigurationException("source is required");
|
||||
}
|
||||
if (!(this.source instanceof PollableSource)) {
|
||||
throw new BeanCreationException("Poller requires a PollableSource, but actual type of '"
|
||||
+ this.source + "' is [" + this.source.getClass() + "]");
|
||||
}
|
||||
this.validated = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Object getObject() throws Exception {
|
||||
if (!this.initialized) {
|
||||
this.initPoller();
|
||||
}
|
||||
return this.poller;
|
||||
}
|
||||
|
||||
public Class<?> getObjectType() {
|
||||
return PollingDispatcher.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void initPoller() {
|
||||
synchronized (this.initializationMonitor) {
|
||||
if (this.initialized) {
|
||||
return;
|
||||
}
|
||||
if (!this.validated) {
|
||||
this.afterPropertiesSet();
|
||||
}
|
||||
if (this.schedule == null) {
|
||||
this.schedule = new PollingSchedule(0);
|
||||
}
|
||||
MessageExchangeTemplate template = this.createMessageExchangeTemplate();
|
||||
this.poller = new PollingDispatcher((PollableSource<?>) this.source, this.schedule, new SimpleDispatcher(), template);
|
||||
this.poller.setMaxMessagesPerPoll(this.maxMessagesPerPoll);
|
||||
this.initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
private MessageExchangeTemplate createMessageExchangeTemplate() {
|
||||
MessageExchangeTemplate template = (this.taskExecutor != null) ?
|
||||
new AsyncMessageExchangeTemplate(this.taskExecutor) : new MessageExchangeTemplate();
|
||||
template.setTransactionManager(this.transactionManager);
|
||||
template.setPropagationBehaviorName(DefaultTransactionDefinition.PREFIX_PROPAGATION + this.propagationBehaviorName);
|
||||
template.setIsolationLevelName(DefaultTransactionDefinition.PREFIX_ISOLATION + this.isolationLevelName);
|
||||
template.setTransactionTimeout(this.transactionTimeout);
|
||||
template.setTransactionReadOnly(this.transactionReadOnly);
|
||||
template.setReceiveTimeout(this.receiveTimeout);
|
||||
template.setSendTimeout(this.sendTimeout);
|
||||
return template;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,11 +24,17 @@ import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.annotation.ChannelAdapter;
|
||||
import org.springframework.integration.annotation.Pollable;
|
||||
import org.springframework.integration.annotation.Poller;
|
||||
import org.springframework.integration.bus.MessageBus;
|
||||
import org.springframework.integration.channel.PollableChannelAdapter;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.dispatcher.PollingDispatcher;
|
||||
import org.springframework.integration.endpoint.InboundChannelAdapter;
|
||||
import org.springframework.integration.endpoint.MessageEndpoint;
|
||||
import org.springframework.integration.message.MessageSource;
|
||||
import org.springframework.integration.message.MethodInvokingSource;
|
||||
import org.springframework.integration.message.PollableSource;
|
||||
import org.springframework.integration.scheduling.PollingSchedule;
|
||||
|
||||
/**
|
||||
* Post-processor for methods annotated with {@link Pollable @Pollable}.
|
||||
@@ -48,9 +54,39 @@ public class PollableAnnotationPostProcessor extends AbstractAnnotationMethodPos
|
||||
source.setMethod(method);
|
||||
ChannelAdapter channelAdapterAnnotation = AnnotationUtils.findAnnotation(bean.getClass(), ChannelAdapter.class);
|
||||
if (channelAdapterAnnotation != null) {
|
||||
Poller pollerAnnotation = AnnotationUtils.findAnnotation(bean.getClass(), Poller.class);
|
||||
if (pollerAnnotation == null) {
|
||||
throw new ConfigurationException("The @Poller annotation is required (at class-level) "
|
||||
+ "when using the @ChannelAdapter annotation with a @Pollable method annotation.");
|
||||
}
|
||||
PollingSchedule schedule = new PollingSchedule(pollerAnnotation.period());
|
||||
schedule.setInitialDelay(pollerAnnotation.initialDelay());
|
||||
schedule.setFixedRate(pollerAnnotation.fixedRate());
|
||||
schedule.setTimeUnit(pollerAnnotation.timeUnit());
|
||||
PollingDispatcher poller = new PollingDispatcher((PollableSource<?>) source, schedule);
|
||||
int maxMessagesPerPoll = pollerAnnotation.maxMessagesPerPoll();
|
||||
if (maxMessagesPerPoll == -1) {
|
||||
// the default is 1 since a MethodInvokingSource might return a non-null value
|
||||
// every time it is invoked, thus producing an infinite number of messages per poll
|
||||
maxMessagesPerPoll = 1;
|
||||
}
|
||||
poller.setMaxMessagesPerPoll(maxMessagesPerPoll);
|
||||
InboundChannelAdapter adapter = new InboundChannelAdapter();
|
||||
adapter.setSource(poller);
|
||||
String channelName = channelAdapterAnnotation.value();
|
||||
PollableChannelAdapter adapter = new PollableChannelAdapter(channelName, source, null);
|
||||
this.getMessageBus().registerChannel(adapter);
|
||||
MessageChannel channel = this.getMessageBus().lookupChannel(channelName);
|
||||
if (channel == null) {
|
||||
adapter.setBeanName(channelName + ".adapter");
|
||||
DirectChannel directChannel = new DirectChannel();
|
||||
directChannel.setBeanName(channelName);
|
||||
this.getMessageBus().registerChannel(directChannel);
|
||||
channel = directChannel;
|
||||
}
|
||||
else {
|
||||
adapter.setBeanName(channelName);
|
||||
}
|
||||
adapter.setTarget(channel);
|
||||
this.getMessageBus().registerEndpoint(adapter);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
@@ -24,10 +24,15 @@ import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.integration.ConfigurationException;
|
||||
import org.springframework.integration.annotation.ChannelAdapter;
|
||||
import org.springframework.integration.bus.MessageBus;
|
||||
import org.springframework.integration.channel.PollableChannelAdapter;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.dispatcher.PollingDispatcher;
|
||||
import org.springframework.integration.endpoint.MessageEndpoint;
|
||||
import org.springframework.integration.endpoint.OutboundChannelAdapter;
|
||||
import org.springframework.integration.handler.MethodInvokingTarget;
|
||||
import org.springframework.integration.message.MessageTarget;
|
||||
import org.springframework.integration.message.PollableSource;
|
||||
import org.springframework.integration.scheduling.PollingSchedule;
|
||||
|
||||
/**
|
||||
* Post-processor for classes annotated with {@link MessageTarget @MessageTarget}.
|
||||
@@ -47,9 +52,29 @@ public class TargetAnnotationPostProcessor extends AbstractAnnotationMethodPostP
|
||||
target.setMethod(method);
|
||||
ChannelAdapter channelAdapterAnnotation = AnnotationUtils.findAnnotation(bean.getClass(), ChannelAdapter.class);
|
||||
if (channelAdapterAnnotation != null) {
|
||||
OutboundChannelAdapter adapter = new OutboundChannelAdapter();
|
||||
String channelName = channelAdapterAnnotation.value();
|
||||
PollableChannelAdapter adapter = new PollableChannelAdapter(channelName, null, target);
|
||||
this.getMessageBus().registerChannel(adapter);
|
||||
MessageChannel channel = this.getMessageBus().lookupChannel(channelName);
|
||||
if (channel == null) {
|
||||
adapter.setBeanName(channelName + ".adapter");
|
||||
DirectChannel directChannel = new DirectChannel();
|
||||
directChannel.setBeanName(channelName);
|
||||
this.getMessageBus().registerChannel(directChannel);
|
||||
channel = directChannel;
|
||||
}
|
||||
else {
|
||||
adapter.setBeanName(channelName);
|
||||
}
|
||||
if (channel instanceof PollableSource) {
|
||||
// TODO: add poller config if period, etc is provided (add to @Pollable)
|
||||
PollingDispatcher poller = new PollingDispatcher((PollableSource<?>) channel, new PollingSchedule(0));
|
||||
adapter.setSource(poller);
|
||||
}
|
||||
else {
|
||||
adapter.setSource(channel);
|
||||
}
|
||||
adapter.setTarget(target);
|
||||
this.getMessageBus().registerEndpoint(adapter);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
@@ -162,12 +162,13 @@
|
||||
MessageTarget. Therefore, either "source" or "target" should be provided (but never both).
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexContent>
|
||||
<xsd:extension base="channelType">
|
||||
<xsd:attribute name="source" type="xsd:string"/>
|
||||
<xsd:attribute name="target" type="xsd:string"/>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="poller" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="id" type="xsd:ID"/>
|
||||
<xsd:attribute name="source" type="xsd:string"/>
|
||||
<xsd:attribute name="target" type="xsd:string"/>
|
||||
<xsd:attribute name="channel" type="xsd:string"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
|
||||
@@ -20,10 +20,13 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.integration.message.CompositeMessage;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageExchangeTemplate;
|
||||
import org.springframework.integration.message.MessageHandlingException;
|
||||
import org.springframework.integration.message.MessageSource;
|
||||
import org.springframework.integration.message.MessageTarget;
|
||||
import org.springframework.integration.message.MessagingException;
|
||||
import org.springframework.integration.scheduling.Schedule;
|
||||
import org.springframework.integration.util.ErrorHandler;
|
||||
|
||||
/**
|
||||
@@ -37,15 +40,17 @@ public abstract class AbstractEndpoint implements MessageEndpoint, BeanNameAware
|
||||
|
||||
private volatile String name;
|
||||
|
||||
private MessageSource<?> source;
|
||||
|
||||
private MessageTarget target;
|
||||
|
||||
private volatile Schedule schedule;
|
||||
|
||||
private volatile ErrorHandler errorHandler;
|
||||
|
||||
private volatile boolean requiresReply = false;
|
||||
private final MessageExchangeTemplate messageExchangeTemplate = new MessageExchangeTemplate();
|
||||
|
||||
|
||||
public void setBeanName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of this endpoint.
|
||||
*/
|
||||
@@ -53,12 +58,36 @@ public abstract class AbstractEndpoint implements MessageEndpoint, BeanNameAware
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether this endpoint should throw an Exception when
|
||||
* it returns an invalid reply Message after handling the request.
|
||||
*/
|
||||
public void setRequiresReply(boolean requiresReply) {
|
||||
this.requiresReply = requiresReply;
|
||||
public void setBeanName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public MessageSource<?> getSource() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
public void setSource(MessageSource<?> source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public MessageTarget getTarget() {
|
||||
return this.target;
|
||||
}
|
||||
|
||||
public void setTarget(MessageTarget target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public Schedule getSchedule() {
|
||||
return this.schedule;
|
||||
}
|
||||
|
||||
public void setSchedule(Schedule schedule) {
|
||||
this.schedule = schedule;
|
||||
}
|
||||
|
||||
protected MessageExchangeTemplate getMessageExchangeTemplate() {
|
||||
return this.messageExchangeTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,49 +100,29 @@ public abstract class AbstractEndpoint implements MessageEndpoint, BeanNameAware
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
public final boolean send(Message<?> requestMessage) {
|
||||
if (requestMessage == null || requestMessage.getPayload() == null) {
|
||||
public final boolean send(Message<?> message) {
|
||||
if (message == null || message.getPayload() == null) {
|
||||
throw new IllegalArgumentException("Message and its payload must not be null");
|
||||
}
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug("endpoint '" + this + "' handling message: " + requestMessage);
|
||||
this.logger.debug("endpoint '" + this + "' processing message: " + message);
|
||||
}
|
||||
try {
|
||||
Message<?> replyMessage = this.handleRequestMessage(requestMessage);
|
||||
if (!this.isValidReplyMessage(replyMessage)) {
|
||||
if (this.requiresReply) {
|
||||
throw new MessageHandlingException(requestMessage,
|
||||
"endpoint requires reply but none was received");
|
||||
}
|
||||
}
|
||||
else if (replyMessage instanceof CompositeMessage) {
|
||||
for (Message<?> nextReply : (CompositeMessage) replyMessage) {
|
||||
this.sendReplyMessage(nextReply, requestMessage);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.sendReplyMessage(replyMessage, requestMessage);
|
||||
}
|
||||
return true;
|
||||
return this.sendInternal(message);
|
||||
}
|
||||
catch (Exception e) {
|
||||
if (e instanceof MessagingException) {
|
||||
this.handleException((MessagingException) e);
|
||||
}
|
||||
else {
|
||||
this.handleException(new MessageHandlingException(requestMessage,
|
||||
this.handleException(new MessageHandlingException(message,
|
||||
"failure occurred in endpoint's send operation", e));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Message<?> handleRequestMessage(Message<?> requestMessage);
|
||||
|
||||
protected abstract boolean isValidReplyMessage(Message<?> replyMessage);
|
||||
|
||||
protected abstract void sendReplyMessage(Message<?> replyMessage, Message<?> requestMessage);
|
||||
|
||||
protected abstract boolean sendInternal(Message<?> message);
|
||||
|
||||
private void handleException(MessagingException exception) {
|
||||
if (this.errorHandler == null) {
|
||||
@@ -125,7 +134,6 @@ public abstract class AbstractEndpoint implements MessageEndpoint, BeanNameAware
|
||||
this.errorHandler.handle(exception);
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return (this.name != null) ? this.name : super.toString();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.endpoint;
|
||||
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.message.CompositeMessage;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageHandlingException;
|
||||
import org.springframework.integration.message.MessageSource;
|
||||
import org.springframework.integration.message.MessageTarget;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public abstract class AbstractRequestReplyEndpoint extends AbstractEndpoint {
|
||||
|
||||
private volatile String inputChannelName;
|
||||
|
||||
private volatile String outputChannelName;
|
||||
|
||||
private volatile boolean requiresReply = false;
|
||||
|
||||
|
||||
public String getInputChannelName() {
|
||||
return this.inputChannelName;
|
||||
}
|
||||
|
||||
public void setInputChannelName(String inputChannelName) {
|
||||
this.inputChannelName = inputChannelName;
|
||||
}
|
||||
|
||||
public String getOutputChannelName() {
|
||||
return this.outputChannelName;
|
||||
}
|
||||
|
||||
public void setOutputChannelName(String outputChannelName) {
|
||||
this.outputChannelName = outputChannelName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether this endpoint should throw an Exception when
|
||||
* it returns an invalid reply Message after handling the request.
|
||||
*/
|
||||
public void setRequiresReply(boolean requiresReply) {
|
||||
this.requiresReply = requiresReply;
|
||||
}
|
||||
|
||||
|
||||
protected boolean sendInternal(Message<?> requestMessage) {
|
||||
Message<?> replyMessage = this.handleRequestMessage(requestMessage);
|
||||
if (!this.isValidReplyMessage(replyMessage)) {
|
||||
if (this.requiresReply) {
|
||||
throw new MessageHandlingException(requestMessage,
|
||||
"endpoint requires reply but none was received");
|
||||
}
|
||||
}
|
||||
else if (replyMessage instanceof CompositeMessage) {
|
||||
for (Message<?> nextReply : (CompositeMessage) replyMessage) {
|
||||
this.sendReplyMessage(nextReply, requestMessage);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.sendReplyMessage(replyMessage, requestMessage);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract Message<?> handleRequestMessage(Message<?> requestMessage);
|
||||
|
||||
protected abstract boolean isValidReplyMessage(Message<?> replyMessage);
|
||||
|
||||
protected abstract void sendReplyMessage(Message<?> replyMessage, Message<?> requestMessage);
|
||||
|
||||
@Override
|
||||
public void setSource(MessageSource<?> source) {
|
||||
if (source instanceof MessageChannel) {
|
||||
this.setInputChannelName(((MessageChannel) source).getName());
|
||||
}
|
||||
super.setSource(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTarget(MessageTarget target) {
|
||||
if (target instanceof MessageChannel) {
|
||||
this.setOutputChannelName(((MessageChannel) target).getName());
|
||||
}
|
||||
super.setTarget(target);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,14 +28,11 @@ import org.springframework.integration.handler.MessageHandler;
|
||||
import org.springframework.integration.message.CompositeMessage;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageBuilder;
|
||||
import org.springframework.integration.message.MessageExchangeTemplate;
|
||||
import org.springframework.integration.message.MessageHandlingException;
|
||||
import org.springframework.integration.message.MessageHeaders;
|
||||
import org.springframework.integration.message.MessageRejectedException;
|
||||
import org.springframework.integration.message.MessageSource;
|
||||
import org.springframework.integration.message.MessageTarget;
|
||||
import org.springframework.integration.message.selector.MessageSelector;
|
||||
import org.springframework.integration.scheduling.Schedule;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -60,20 +57,16 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class DefaultEndpoint<T extends MessageHandler> extends AbstractEndpoint implements ChannelRegistryAware {
|
||||
public class DefaultEndpoint<T extends MessageHandler> extends AbstractRequestReplyEndpoint implements ChannelRegistryAware {
|
||||
|
||||
private final T handler;
|
||||
|
||||
private volatile MessageChannel outputChannel;
|
||||
|
||||
private volatile ChannelRegistry channelRegistry;
|
||||
|
||||
private volatile MessageSelector selector;
|
||||
|
||||
private final List<EndpointInterceptor> interceptors = new ArrayList<EndpointInterceptor>();
|
||||
|
||||
private final MessageExchangeTemplate messageExchangeTemplate = new MessageExchangeTemplate();
|
||||
|
||||
|
||||
/**
|
||||
* Create an endpoint for the given handler.
|
||||
@@ -83,15 +76,6 @@ public class DefaultEndpoint<T extends MessageHandler> extends AbstractEndpoint
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify the channel where reply Messages should be sent if
|
||||
* no 'nextTarget' header value is available on the reply Message.
|
||||
*/
|
||||
public void setOutputChannel(MessageChannel outputChannel) {
|
||||
this.outputChannel = outputChannel;
|
||||
}
|
||||
|
||||
protected T getHandler() {
|
||||
return this.handler;
|
||||
}
|
||||
@@ -127,7 +111,7 @@ public class DefaultEndpoint<T extends MessageHandler> extends AbstractEndpoint
|
||||
* target. The default value indicates an indefinite timeout.
|
||||
*/
|
||||
public void setReplyTimeout(long replyTimeout) {
|
||||
this.messageExchangeTemplate.setSendTimeout(replyTimeout);
|
||||
this.getMessageExchangeTemplate().setSendTimeout(replyTimeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -170,7 +154,7 @@ public class DefaultEndpoint<T extends MessageHandler> extends AbstractEndpoint
|
||||
replyMessage = MessageBuilder.fromMessage(replyMessage)
|
||||
.copyHeadersIfAbsent(requestMessage.getHeaders())
|
||||
.setHeaderIfAbsent(MessageHeaders.CORRELATION_ID, requestMessage.getHeaders().getId()).build();
|
||||
if (!this.messageExchangeTemplate.send(replyMessage, replyTarget)) {
|
||||
if (!this.getMessageExchangeTemplate().send(replyMessage, replyTarget)) {
|
||||
throw new MessageEndpointReplyException(replyMessage, requestMessage,
|
||||
"failed to send reply to '" + replyTarget + "'");
|
||||
}
|
||||
@@ -221,7 +205,7 @@ public class DefaultEndpoint<T extends MessageHandler> extends AbstractEndpoint
|
||||
private MessageTarget resolveReplyTarget(Message<?> replyMessage, MessageHeaders requestHeaders) {
|
||||
MessageTarget replyTarget = this.resolveTargetAttribute(replyMessage.getHeaders().getNextTarget());
|
||||
if (replyTarget == null) {
|
||||
replyTarget = this.outputChannel;
|
||||
replyTarget = this.getTarget();
|
||||
}
|
||||
if (replyTarget == null) {
|
||||
replyTarget = this.resolveTargetAttribute(requestHeaders.getReturnAddress());
|
||||
@@ -245,54 +229,17 @@ public class DefaultEndpoint<T extends MessageHandler> extends AbstractEndpoint
|
||||
return replyTarget;
|
||||
}
|
||||
|
||||
/* TODO: the following properties/methods are candidates for removal from the MessageEndpoint interface. */
|
||||
// TODO: remove
|
||||
|
||||
private volatile String inputChannelName;
|
||||
private volatile String outputChannelName;
|
||||
private volatile MessageSource<?> source;
|
||||
private volatile Schedule schedule;
|
||||
|
||||
public String getInputChannelName() {
|
||||
return this.inputChannelName;
|
||||
public void setReturnAddressOverrides(boolean returnAddressOverrides) {
|
||||
}
|
||||
|
||||
public void setInputChannelName(String inputChannelName) {
|
||||
this.inputChannelName = inputChannelName;
|
||||
}
|
||||
|
||||
public String getOutputChannelName() {
|
||||
return this.outputChannelName;
|
||||
}
|
||||
|
||||
public void setOutputChannelName(String outputChannelName) {
|
||||
this.outputChannelName = outputChannelName;
|
||||
}
|
||||
|
||||
public void setReturnAddressOverrides(boolean b) {
|
||||
}
|
||||
|
||||
public Schedule getSchedule() {
|
||||
return this.schedule;
|
||||
}
|
||||
|
||||
public void setSchedule(Schedule schedule) {
|
||||
this.schedule = schedule;
|
||||
}
|
||||
|
||||
public MessageSource<?> getSource() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
public MessageTarget getTarget() {
|
||||
return this.outputChannel;
|
||||
}
|
||||
|
||||
public void setSource(MessageSource<?> source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public void setTarget(MessageTarget target) {
|
||||
this.outputChannel = (MessageChannel) target;
|
||||
/**
|
||||
* Specify the channel where reply Messages should be sent if
|
||||
* no 'nextTarget' header value is available on the reply Message.
|
||||
*/
|
||||
public void setOutputChannel(MessageChannel outputChannel) {
|
||||
this.setTarget(outputChannel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.endpoint;
|
||||
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageDeliveryAware;
|
||||
import org.springframework.integration.message.MessageDeliveryException;
|
||||
import org.springframework.integration.message.MessagingException;
|
||||
|
||||
/**
|
||||
* A Channel Adapter implementation for connecting a
|
||||
* {@link org.springframework.integration.message.MessageSource}
|
||||
* to a {@link MessageChannel}.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class InboundChannelAdapter extends AbstractEndpoint {
|
||||
|
||||
@Override
|
||||
protected boolean sendInternal(Message<?> message) {
|
||||
try {
|
||||
boolean sent = this.getMessageExchangeTemplate().send(message, this.getTarget());
|
||||
if (sent && this.getSource() instanceof MessageDeliveryAware) {
|
||||
((MessageDeliveryAware) this.getSource()).onSend(message);
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
catch (Exception e) {
|
||||
MessagingException exception = (e instanceof MessagingException) ? (MessagingException) e
|
||||
: new MessageDeliveryException(message, "channel-adapter failed to send message to target");
|
||||
if (this.getSource() instanceof MessageDeliveryAware) {
|
||||
((MessageDeliveryAware) this.getSource()).onFailure(exception);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getInputChannelName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getOutputChannelName() {
|
||||
if (this.getTarget() instanceof MessageChannel) {
|
||||
return ((MessageChannel) this.getTarget()).getName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setInputChannelName(String inputChannelName) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.endpoint;
|
||||
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.message.Message;
|
||||
|
||||
/**
|
||||
* A Channel Adapter implementation for connecting a {@link MessageChannel}
|
||||
* to a {@link org.springframework.integration.message.MessageTarget}.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class OutboundChannelAdapter extends AbstractEndpoint {
|
||||
|
||||
@Override
|
||||
protected boolean sendInternal(Message<?> message) {
|
||||
return this.getMessageExchangeTemplate().send(message, this.getTarget());
|
||||
}
|
||||
|
||||
public String getInputChannelName() {
|
||||
if (this.getSource() instanceof MessageChannel) {
|
||||
return ((MessageChannel) this.getSource()).getName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getOutputChannelName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setInputChannelName(String inputChannelName) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,6 +32,7 @@ import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallback;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* This is the central class for invoking message exchange operations
|
||||
@@ -192,6 +193,7 @@ public class MessageExchangeTemplate implements InitializingBean {
|
||||
|
||||
|
||||
private boolean doSend(Message<?> message, MessageTarget target) {
|
||||
Assert.notNull(target, "target must not be null");
|
||||
long timeout = this.sendTimeout;
|
||||
boolean sent = (timeout >= 0 && target instanceof BlockingTarget)
|
||||
? ((BlockingTarget) target).send(message, timeout)
|
||||
@@ -203,6 +205,7 @@ public class MessageExchangeTemplate implements InitializingBean {
|
||||
}
|
||||
|
||||
private Message<?> doReceive(PollableSource<?> source) {
|
||||
Assert.notNull(source, "source must not be null");
|
||||
long timeout = this.receiveTimeout;
|
||||
Message<?> message = (timeout >= 0 && source instanceof BlockingSource)
|
||||
? ((BlockingSource<?>) source).receive(timeout)
|
||||
|
||||
@@ -30,10 +30,10 @@ import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.integration.channel.ChannelRegistry;
|
||||
import org.springframework.integration.channel.PollableChannel;
|
||||
import org.springframework.integration.channel.PollableChannelAdapter;
|
||||
import org.springframework.integration.channel.PublishSubscribeChannel;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.endpoint.DefaultEndpoint;
|
||||
import org.springframework.integration.endpoint.InboundChannelAdapter;
|
||||
import org.springframework.integration.handler.MessageHandler;
|
||||
import org.springframework.integration.message.ErrorMessage;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
@@ -223,17 +223,10 @@ public class DefaultMessageBusTests {
|
||||
public void testErrorChannelWithFailedDispatch() throws InterruptedException {
|
||||
MessageBus bus = new DefaultMessageBus();
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
PollableChannelAdapter channelAdapter = new PollableChannelAdapter(
|
||||
"testChannel", new FailingSource(latch), null);
|
||||
MessageHandler handler = new MessageHandler() {
|
||||
public Message<?> handle(Message<?> message) {
|
||||
return message;
|
||||
}
|
||||
};
|
||||
DefaultEndpoint<MessageHandler> endpoint = new DefaultEndpoint<MessageHandler>(handler);
|
||||
endpoint.setBeanName("testEndpoint");
|
||||
endpoint.setSource(channelAdapter);
|
||||
bus.registerEndpoint(endpoint);
|
||||
InboundChannelAdapter channelAdapter = new InboundChannelAdapter();
|
||||
channelAdapter.setSource(new FailingSource(latch));
|
||||
channelAdapter.setBeanName("testChannel");
|
||||
bus.registerEndpoint(channelAdapter);
|
||||
bus.start();
|
||||
latch.await(2000, TimeUnit.MILLISECONDS);
|
||||
Message<?> message = ((PollableChannel) bus.getErrorChannel()).receive(5000);
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.channel.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.channel.PollableChannel;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class ChannelAdapterFactoryBeanContextTests {
|
||||
|
||||
@Test
|
||||
public void testPollableSourceWithoutTarget() throws Exception {
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"channelAdapterFactoryBeanTests.xml", this.getClass());
|
||||
MessageChannel channel = (MessageChannel)
|
||||
context.getBean("adapterWithPollableSourceAndNoTarget");
|
||||
assertTrue(channel instanceof PollableChannel);
|
||||
assertEquals("adapterWithPollableSourceAndNoTarget", channel.getName());
|
||||
Message<?> reply = ((PollableChannel) channel).receive();
|
||||
assertNotNull(reply);
|
||||
assertEquals("test", reply.getPayload());
|
||||
assertFalse(channel.send(new StringMessage("no target")));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.channel.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.channel.PollableChannel;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.MessageTarget;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
import org.springframework.integration.message.SubscribableSource;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class ChannelAdapterFactoryBeanTests {
|
||||
|
||||
@Test
|
||||
public void testPollableSourceWithoutTarget() throws Exception {
|
||||
ChannelAdapterFactoryBean factoryBean = new ChannelAdapterFactoryBean();
|
||||
factoryBean.setBeanName("testChannel");
|
||||
factoryBean.setSource(new TestPollableSource());
|
||||
Object bean = factoryBean.getObject();
|
||||
assertTrue(bean instanceof PollableChannel);
|
||||
PollableChannel channel = (PollableChannel) bean;
|
||||
Message<?> reply = channel.receive();
|
||||
assertNotNull(reply);
|
||||
assertEquals("test", reply.getPayload());
|
||||
assertFalse(channel.send(new StringMessage("no target")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscribableSourceWithoutTarget() throws Exception {
|
||||
ChannelAdapterFactoryBean factoryBean = new ChannelAdapterFactoryBean();
|
||||
factoryBean.setBeanName("testChannel");
|
||||
TestSubscribableSource source = new TestSubscribableSource();
|
||||
factoryBean.setSource(source);
|
||||
Object bean = factoryBean.getObject();
|
||||
assertTrue(bean instanceof MessageChannel);
|
||||
assertTrue(bean instanceof SubscribableSource);
|
||||
MessageChannel channel = (MessageChannel) bean;
|
||||
final AtomicReference<Message<?>> messageReference = new AtomicReference<Message<?>>();
|
||||
((SubscribableSource) bean).subscribe(new MessageTarget() {
|
||||
public boolean send(Message<?> message) {
|
||||
messageReference.set(message);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
source.publishMessage(new StringMessage("foo"));
|
||||
assertNotNull(messageReference.get());
|
||||
assertEquals("foo", (messageReference.get()).getPayload());
|
||||
assertFalse(channel.send(new StringMessage("no target")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTargetOnly() throws Exception {
|
||||
ChannelAdapterFactoryBean factoryBean = new ChannelAdapterFactoryBean();
|
||||
factoryBean.setBeanName("testChannel");
|
||||
final AtomicReference<Message<?>> messageRef = new AtomicReference<Message<?>>();
|
||||
factoryBean.setTarget(new MessageTarget() {
|
||||
public boolean send(Message<?> message) {
|
||||
messageRef.set(message);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
Object bean = factoryBean.getObject();
|
||||
assertTrue(bean instanceof PollableChannel);
|
||||
PollableChannel channel = (PollableChannel) bean;
|
||||
Message<?> reply = channel.receive(0);
|
||||
assertNull(reply);
|
||||
assertTrue(channel.send(new StringMessage("hello")));
|
||||
assertNotNull(messageRef.get());
|
||||
assertEquals("hello", messageRef.get().getPayload());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:si="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration-core-1.0.xsd">
|
||||
|
||||
<bean id="adapterWithPollableSourceAndNoTarget" class="org.springframework.integration.channel.config.ChannelAdapterFactoryBean">
|
||||
<property name="source" ref="pollableSource"/>
|
||||
</bean>
|
||||
|
||||
<bean id="adapterWithPollableSourceAndTarget" class="org.springframework.integration.channel.config.ChannelAdapterFactoryBean">
|
||||
<property name="source" ref="pollableSource"/>
|
||||
<property name="target" ref="testTarget"/>
|
||||
</bean>
|
||||
|
||||
<bean id="pollableSource" class="org.springframework.integration.channel.config.TestPollableSource"/>
|
||||
|
||||
<bean id="testTarget" class="org.springframework.integration.channel.config.TestTarget"/>
|
||||
|
||||
</beans>
|
||||
@@ -9,9 +9,7 @@
|
||||
|
||||
<message-bus/>
|
||||
|
||||
<channel-adapter id="targetOnly" target="target"/>
|
||||
|
||||
<channel-adapter id="targetWithDatatype" target="target" datatype="java.lang.String"/>
|
||||
<channel-adapter id="outboundWithImplicitChannel" target="target"/>
|
||||
|
||||
<beans:bean id="target" class="org.springframework.integration.config.TestTarget"/>
|
||||
|
||||
|
||||
@@ -16,15 +16,18 @@
|
||||
|
||||
package org.springframework.integration.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.integration.bus.MessageBus;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.channel.PollableChannel;
|
||||
import org.springframework.integration.channel.PollableChannelAdapter;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.message.MessageDeliveryException;
|
||||
import org.springframework.integration.endpoint.OutboundChannelAdapter;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
|
||||
@@ -37,24 +40,20 @@ public class ChannelAdapterParserTests extends AbstractJUnit4SpringContextTests
|
||||
|
||||
@Test
|
||||
public void targetOnly() {
|
||||
Object bean = this.applicationContext.getBean("targetOnly");
|
||||
assertTrue(bean instanceof MessageChannel);
|
||||
assertTrue(bean instanceof PollableChannel);
|
||||
assertTrue(bean instanceof PollableChannelAdapter);
|
||||
MessageChannel channel = (MessageChannel) bean;
|
||||
assertTrue(channel.send(new StringMessage("test")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetWithDatatypeAccepts() {
|
||||
MessageChannel channel = (MessageChannel) this.applicationContext.getBean("targetWithDatatype");
|
||||
assertTrue(channel.send(new StringMessage("test")));
|
||||
}
|
||||
|
||||
@Test(expected = MessageDeliveryException.class)
|
||||
public void targetWithDatatypeRejects() {
|
||||
MessageChannel channel = (MessageChannel) this.applicationContext.getBean("targetWithDatatype");
|
||||
channel.send(new GenericMessage<Integer>(123));
|
||||
String beanName = "outboundWithImplicitChannel";
|
||||
Object channel = this.applicationContext.getBean(beanName);
|
||||
assertTrue(channel instanceof DirectChannel);
|
||||
MessageBus bus = (MessageBus) this.applicationContext.getBean(MessageBusParser.MESSAGE_BUS_BEAN_NAME);
|
||||
assertNotNull(bus.lookupChannel(beanName));
|
||||
Object adapter = bus.lookupEndpoint(beanName + ".adapter");
|
||||
assertNotNull(adapter);
|
||||
assertTrue(adapter instanceof OutboundChannelAdapter);
|
||||
TestTarget target = (TestTarget) this.applicationContext.getBean("target");
|
||||
assertNull(target.getLastMessage());
|
||||
Message<?> message = new StringMessage("test");
|
||||
assertTrue(((MessageChannel) channel).send(message));
|
||||
assertNotNull(target.getLastMessage());
|
||||
assertEquals(message, target.getLastMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,15 @@ import org.springframework.integration.message.MessageTarget;
|
||||
*/
|
||||
public class TestTarget implements MessageTarget {
|
||||
|
||||
private volatile Message<?> lastMessage;
|
||||
|
||||
|
||||
public Message<?> getLastMessage() {
|
||||
return this.lastMessage;
|
||||
}
|
||||
|
||||
public boolean send(Message<?> message) {
|
||||
this.lastMessage = message;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,12 +29,12 @@ import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.core.annotation.Order;
|
||||
@@ -52,6 +52,7 @@ import org.springframework.integration.bus.DefaultMessageBus;
|
||||
import org.springframework.integration.bus.MessageBus;
|
||||
import org.springframework.integration.channel.ChannelRegistry;
|
||||
import org.springframework.integration.channel.ChannelRegistryAware;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.channel.PollableChannel;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
@@ -91,22 +92,24 @@ public class MessagingAnnotationPostProcessorTests {
|
||||
|
||||
@Test
|
||||
public void testSimpleHandlerWithContext() {
|
||||
ApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
AbstractApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"handlerAnnotationPostProcessorTests.xml", this.getClass());
|
||||
MessageHandler handler = (MessageHandler) context.getBean("simpleHandler");
|
||||
Message<?> reply = handler.handle(new StringMessage("world"));
|
||||
assertEquals("hello world", reply.getPayload());
|
||||
context.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleHandlerEndpointWithContext() {
|
||||
ApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
AbstractApplicationContext context = new ClassPathXmlApplicationContext(
|
||||
"handlerAnnotationPostProcessorTests.xml", this.getClass());
|
||||
MessageChannel inputChannel = (MessageChannel) context.getBean("inputChannel");
|
||||
PollableChannel outputChannel = (PollableChannel) context.getBean("outputChannel");
|
||||
inputChannel.send(new StringMessage("foo"));
|
||||
Message<?> reply = outputChannel.receive(1000);
|
||||
assertEquals("hello foo", reply.getPayload());
|
||||
context.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -381,16 +384,27 @@ public class MessagingAnnotationPostProcessorTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChannelAdapterAnnotation() {
|
||||
public void testChannelAdapterAnnotation() throws InterruptedException {
|
||||
MessageBus messageBus = new DefaultMessageBus();
|
||||
MessagingAnnotationPostProcessor postProcessor = new MessagingAnnotationPostProcessor(messageBus);
|
||||
postProcessor.afterPropertiesSet();
|
||||
ChannelAdapterAnnotationTestBean testBean = new ChannelAdapterAnnotationTestBean();
|
||||
postProcessor.postProcessAfterInitialization(testBean, "testBean");
|
||||
messageBus.start();
|
||||
PollableChannel testChannel = (PollableChannel) messageBus.lookupChannel("testChannel");
|
||||
Message<?> message = testChannel.receive(1000);
|
||||
assertEquals("test", message.getPayload());
|
||||
DirectChannel testChannel = (DirectChannel) messageBus.lookupChannel("testChannel");
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final AtomicReference<Message<?>> receivedMessage = new AtomicReference<Message<?>>();
|
||||
testChannel.subscribe(new org.springframework.integration.message.MessageTarget() {
|
||||
public boolean send(Message<?> message) {
|
||||
receivedMessage.set(message);
|
||||
latch.countDown();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
latch.await(3, TimeUnit.SECONDS);
|
||||
assertEquals(0, latch.getCount());
|
||||
assertNotNull(receivedMessage.get());
|
||||
assertEquals("test", receivedMessage.get().getPayload());
|
||||
messageBus.stop();
|
||||
}
|
||||
|
||||
@@ -534,6 +548,7 @@ public class MessagingAnnotationPostProcessorTests {
|
||||
|
||||
|
||||
@ChannelAdapter("testChannel")
|
||||
@Poller(period = 1000, initialDelay = 0, maxMessagesPerPoll = 1)
|
||||
private static class ChannelAdapterAnnotationTestBean {
|
||||
|
||||
@Pollable
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 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.handler;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.support.AbstractApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.channel.PollableChannel;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class MethodInvokingAdapterTests {
|
||||
|
||||
@Test
|
||||
public void testMethodInvokingSourceChannelAdapter() throws IOException, InterruptedException {
|
||||
AbstractApplicationContext context = new ClassPathXmlApplicationContext("adapterTests.xml", this.getClass());
|
||||
PollableChannel channel = (PollableChannel) context.getBean("sourceChannelAdapter");
|
||||
Message<?> message = channel.receive(1000);
|
||||
assertNotNull(message);
|
||||
assertEquals("foo", message.getPayload());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethodInvokingTargetChannelAdapter() throws IOException, InterruptedException {
|
||||
AbstractApplicationContext context = new ClassPathXmlApplicationContext("adapterTests.xml", this.getClass());
|
||||
MessageChannel channel = (MessageChannel) context.getBean("targetChannelAdapter");
|
||||
TestSink sink = (TestSink) context.getBean("sink");
|
||||
assertNull(sink.get());
|
||||
channel.send(new StringMessage("foo"));
|
||||
String result = sink.get();
|
||||
assertNotNull(result);
|
||||
assertEquals("foo", result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
<bean id="sourceChannelAdapter" class="org.springframework.integration.channel.config.ChannelAdapterFactoryBean">
|
||||
<property name="source" ref="source"/>
|
||||
</bean>
|
||||
|
||||
<bean id="source" class="org.springframework.integration.message.MethodInvokingSource">
|
||||
<property name="object">
|
||||
<bean class="org.springframework.integration.handler.TestSource"/>
|
||||
</property>
|
||||
<property name="methodName" value="foo"/>
|
||||
</bean>
|
||||
|
||||
<bean id="targetChannelAdapter" class="org.springframework.integration.channel.config.ChannelAdapterFactoryBean">
|
||||
<property name="target" ref="target"/>
|
||||
</bean>
|
||||
|
||||
<bean id="target" class="org.springframework.integration.handler.MethodInvokingTarget">
|
||||
<property name="object" ref="sink"/>
|
||||
<property name="methodName" value="store"/>
|
||||
</bean>
|
||||
|
||||
<bean id="sink" class="org.springframework.integration.handler.TestSink"/>
|
||||
|
||||
</beans>
|
||||
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:si="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration-core-1.0.xsd">
|
||||
|
||||
<si:message-bus auto-startup="false"/>
|
||||
|
||||
<si:channel id="channel"/>
|
||||
|
||||
<si:channel-adapter source="source" method="foo" channel="channel">
|
||||
<si:schedule period="100"/>
|
||||
</si:channel-adapter>
|
||||
|
||||
<si:channel-adapter target="sink" method="store" channel="channel"/>
|
||||
|
||||
<bean id="source" class="org.springframework.integration.handler.TestSource"/>
|
||||
|
||||
<bean id="sink" class="org.springframework.integration.handler.TestSink"/>
|
||||
|
||||
</beans>
|
||||
Reference in New Issue
Block a user