The <jms-gateway/> element is now available for message-driven JMS adapters. The <jms-source/> is strictly for polling adapters. Provided basic foundation for converting other request-reply adapters into "gateways". This includes the following namespace changes: 'send-timeout' is now 'request-timeout', 'receive-timeout' is now 'reply-timeout', and the 'channel' element is now 'request-channel'. The Source interface now includes the receive() method itself. PollableSource and SubscribableSource interfaces have both been removed. The Subscribable interface was added (e.g. for SynchronousChannel), but "gateway" adapter types will be configured directly with a request channel (and optionally a response channel).

This commit is contained in:
Mark Fisher
2008-05-03 22:23:40 +00:00
parent 4f42fe7227
commit 4c0c3677d0
53 changed files with 460 additions and 415 deletions

View File

@@ -23,7 +23,7 @@ import org.springframework.integration.ConfigurationException;
import org.springframework.integration.handler.HandlerMethodInvoker;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.PollableSource;
import org.springframework.integration.message.Source;
import org.springframework.integration.util.MethodValidator;
import org.springframework.util.Assert;
@@ -33,7 +33,7 @@ import org.springframework.util.Assert;
*
* @author Mark Fisher
*/
public class MethodInvokingSource<T> implements PollableSource<Object>, InitializingBean {
public class MethodInvokingSource<T> implements Source<Object>, InitializingBean {
private T object;

View File

@@ -18,11 +18,9 @@ package org.springframework.integration.channel;
import java.util.List;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.integration.ConfigurationException;
import org.springframework.integration.config.MessageBusParser;
import org.springframework.integration.bus.MessageBus;
import org.springframework.integration.bus.MessageBusAware;
import org.springframework.integration.endpoint.EndpointRegistry;
import org.springframework.integration.endpoint.HandlerEndpoint;
import org.springframework.integration.handler.ReplyHandler;
@@ -38,7 +36,7 @@ import org.springframework.integration.scheduling.Subscription;
*
* @author Mark Fisher
*/
public class RequestReplyTemplate implements ApplicationContextAware {
public class RequestReplyTemplate implements MessageBusAware {
private MessageChannel requestChannel;
@@ -122,9 +120,9 @@ public class RequestReplyTemplate implements ApplicationContextAware {
this.endpointRegistry = endpointRegistry;
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (applicationContext.containsBean(MessageBusParser.MESSAGE_BUS_BEAN_NAME)) {
this.setEndpointRegistry((EndpointRegistry) applicationContext.getBean(MessageBusParser.MESSAGE_BUS_BEAN_NAME));
public void setMessageBus(MessageBus messageBus) {
if (this.endpointRegistry == null) {
this.setEndpointRegistry(messageBus);
}
}

View File

@@ -23,7 +23,6 @@ import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.ConfigurationException;
import org.springframework.integration.endpoint.PollingSourceEndpoint;
import org.springframework.integration.endpoint.SimpleSourceEndpoint;
import org.springframework.integration.scheduling.PollingSchedule;
import org.springframework.integration.scheduling.Schedule;
import org.springframework.util.StringUtils;
@@ -37,10 +36,7 @@ import org.springframework.util.xml.DomUtils;
public class SourceEndpointParser extends AbstractSimpleBeanDefinitionParser {
protected final Class<?> getBeanClass(Element element) {
if (this.getScheduleElement(element) != null) {
return PollingSourceEndpoint.class;
}
return SimpleSourceEndpoint.class;
return PollingSourceEndpoint.class;
}
protected boolean shouldGenerateId() {
@@ -68,9 +64,10 @@ public class SourceEndpointParser extends AbstractSimpleBeanDefinitionParser {
builder.addConstructorArgReference(source);
builder.addConstructorArgReference(output);
Element scheduleElement = this.getScheduleElement(element);
if (scheduleElement != null) {
builder.addConstructorArgValue(this.parseSchedule(scheduleElement));
if (scheduleElement == null) {
throw new ConfigurationException("The <schedule/> sub-element is required for a <source-endpoint/>.");
}
builder.addConstructorArgValue(this.parseSchedule(scheduleElement));
}
/**

View File

@@ -25,7 +25,7 @@ import org.springframework.integration.message.BlockingSource;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageDeliveryAware;
import org.springframework.integration.message.MessageDeliveryException;
import org.springframework.integration.message.PollableSource;
import org.springframework.integration.message.Source;
import org.springframework.util.Assert;
/**
@@ -46,14 +46,14 @@ import org.springframework.util.Assert;
*/
public class DefaultPollingDispatcher extends SimpleDispatcher implements PollingDispatcher {
private final PollableSource<?> source;
private final Source<?> source;
public DefaultPollingDispatcher(MessageChannel channel) {
this(channel, channel.getDispatcherPolicy());
}
public DefaultPollingDispatcher(PollableSource<?> source, DispatcherPolicy dispatcherPolicy) {
public DefaultPollingDispatcher(Source<?> source, DispatcherPolicy dispatcherPolicy) {
super(dispatcherPolicy);
Assert.notNull(source, "source must not be null");
this.source = source;

View File

@@ -17,11 +17,11 @@
package org.springframework.integration.dispatcher;
import org.springframework.integration.message.Poller;
import org.springframework.integration.message.SubscribableSource;
import org.springframework.integration.message.Subscribable;
/**
* @author Mark Fisher
*/
public interface PollingDispatcher extends Poller, MessageDispatcher, SubscribableSource {
public interface PollingDispatcher extends Poller, MessageDispatcher, Subscribable {
}

View File

@@ -30,7 +30,7 @@ import org.springframework.integration.handler.MessageHandlerRejectedExecutionEx
import org.springframework.integration.message.BlockingTarget;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageDeliveryException;
import org.springframework.integration.message.SubscribableSource;
import org.springframework.integration.message.Subscribable;
import org.springframework.integration.message.Target;
/**
@@ -38,7 +38,7 @@ import org.springframework.integration.message.Target;
*
* @author Mark Fisher
*/
public class SimpleDispatcher implements MessageDispatcher, SubscribableSource {
public class SimpleDispatcher implements MessageDispatcher, Subscribable {
protected final Log logger = LogFactory.getLog(this.getClass());

View File

@@ -26,8 +26,8 @@ import org.springframework.integration.channel.AbstractMessageChannel;
import org.springframework.integration.channel.DispatcherPolicy;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.PollableSource;
import org.springframework.integration.message.SubscribableSource;
import org.springframework.integration.message.Source;
import org.springframework.integration.message.Subscribable;
import org.springframework.integration.message.Target;
import org.springframework.integration.message.selector.MessageSelector;
@@ -45,12 +45,12 @@ import org.springframework.integration.message.selector.MessageSelector;
* @author Dave Syer
* @author Mark Fisher
*/
public class SynchronousChannel extends AbstractMessageChannel implements SubscribableSource {
public class SynchronousChannel extends AbstractMessageChannel implements Subscribable {
private static final ThreadLocalMessageHolder messageHolder = new ThreadLocalMessageHolder();
private volatile PollableSource<?> source;
private volatile Source<?> source;
private final SimpleDispatcher dispatcher;
@@ -61,14 +61,14 @@ public class SynchronousChannel extends AbstractMessageChannel implements Subscr
this(null);
}
public SynchronousChannel(PollableSource<?> source) {
public SynchronousChannel(Source<?> source) {
super(defaultDispatcherPolicy());
this.source = source;
this.dispatcher = new SimpleDispatcher(this.getDispatcherPolicy());
}
public void setSource(PollableSource<?> source) {
public void setSource(Source<?> source) {
this.source = source;
}

View File

@@ -32,14 +32,14 @@ public abstract class AbstractSourceEndpoint implements SourceEndpoint {
protected final Log logger = LogFactory.getLog(this.getClass());
private final Source source;
private final Source<?> source;
private final MessageChannel channel;
private volatile String name;
public AbstractSourceEndpoint(Source source, MessageChannel channel) {
public AbstractSourceEndpoint(Source<?> source, MessageChannel channel) {
Assert.notNull(source, "source must not be null");
Assert.notNull(channel, "channel must not be null");
this.source = source;
@@ -47,7 +47,7 @@ public abstract class AbstractSourceEndpoint implements SourceEndpoint {
}
public Source getSource() {
public Source<?> getSource() {
return this.source;
}

View File

@@ -29,7 +29,7 @@ import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.dispatcher.DefaultPollingDispatcher;
import org.springframework.integration.dispatcher.PollingDispatcher;
import org.springframework.integration.dispatcher.PollingDispatcherTask;
import org.springframework.integration.message.PollableSource;
import org.springframework.integration.message.Source;
import org.springframework.integration.scheduling.MessagingTask;
import org.springframework.integration.scheduling.PollingSchedule;
import org.springframework.integration.scheduling.Schedule;
@@ -60,7 +60,7 @@ public class PollingSourceEndpoint extends AbstractSourceEndpoint implements Mes
private final Object taskMonitor = new Object();
public PollingSourceEndpoint(PollableSource<?> source, MessageChannel channel, PollingSchedule schedule) {
public PollingSourceEndpoint(Source<?> source, MessageChannel channel, PollingSchedule schedule) {
super(source, channel);
Assert.notNull(schedule, "schedule must not be null");
this.dispatcher = new DefaultPollingDispatcher(source, this.dispatcherPolicy);

View File

@@ -1,32 +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.endpoint;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.message.SubscribableSource;
/**
* @author Mark Fisher
*/
public class SimpleSourceEndpoint extends AbstractSourceEndpoint {
public SimpleSourceEndpoint(SubscribableSource source, MessageChannel channel) {
super(source, channel);
source.subscribe(channel);
}
}

View File

@@ -23,8 +23,12 @@ import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.SimpleTypeConverter;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.integration.bus.MessageBus;
import org.springframework.integration.config.MessageBusParser;
import org.springframework.integration.message.Message;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -35,7 +39,8 @@ import org.springframework.util.ClassUtils;
*
* @author Mark Fisher
*/
public class GatewayProxyFactoryBean extends MessagingGateway implements FactoryBean, MethodInterceptor, InitializingBean, BeanClassLoaderAware {
public class GatewayProxyFactoryBean extends MessagingGateway
implements FactoryBean, MethodInterceptor, InitializingBean, BeanClassLoaderAware, BeanFactoryAware {
private Class<?> serviceInterface;
@@ -59,6 +64,11 @@ public class GatewayProxyFactoryBean extends MessagingGateway implements Factory
this.beanClassLoader = beanClassLoader;
}
public void setBeanFactory(BeanFactory beanFactory) {
this.getRequestReplyTemplate().setMessageBus(
(MessageBus) beanFactory.getBean(MessageBusParser.MESSAGE_BUS_BEAN_NAME));
}
public void afterPropertiesSet() {
this.serviceProxy = new ProxyFactory(this.serviceInterface, this).getProxy(this.beanClassLoader);
}
@@ -84,7 +94,7 @@ public class GatewayProxyFactoryBean extends MessagingGateway implements Factory
if (shouldReturnMessage) {
return this.receive();
}
response = this.invoke();
response = this.receive();
}
else {
Object payload = (paramCount == 1) ? invocation.getArguments()[0] : invocation.getArguments();
@@ -92,7 +102,7 @@ public class GatewayProxyFactoryBean extends MessagingGateway implements Factory
this.send(payload);
return null;
}
response = this.invoke(payload, !shouldReturnMessage);
response = shouldReturnMessage ? this.sendAndReceiveMessage(payload) : this.sendAndReceive(payload);
}
return (response != null) ? this.typeConverter.convertIfNecessary(response, returnType) : null;
}

View File

@@ -33,19 +33,17 @@ import org.springframework.util.Assert;
*
* @author Mark Fisher
*/
public class MessagingGateway extends RequestReplyTemplate {
public class MessagingGateway {
private final RequestReplyTemplate requestReplyTemplate = new RequestReplyTemplate();
private MessageCreator messageCreator = new DefaultMessageCreator();
private MessageMapper messageMapper = new DefaultMessageMapper();
public MessagingGateway(MessageChannel requestChannel, MessageChannel replyChannel) {
super(requestChannel, replyChannel);
}
public MessagingGateway(MessageChannel requestChannel) {
super(requestChannel);
this.requestReplyTemplate.setRequestChannel(requestChannel);
}
public MessagingGateway() {
@@ -53,6 +51,22 @@ public class MessagingGateway extends RequestReplyTemplate {
}
public void setRequestChannel(MessageChannel requestChannel) {
this.requestReplyTemplate.setRequestChannel(requestChannel);
}
public void setReplyChannel(MessageChannel replyChannel) {
this.requestReplyTemplate.setReplyChannel(replyChannel);
}
public void setRequestTimeout(long requestTimeout) {
this.requestReplyTemplate.setRequestTimeout(requestTimeout);
}
public void setReplyTimeout(long replyTimeout) {
this.requestReplyTemplate.setReplyTimeout(replyTimeout);
}
public void setMessageCreator(MessageCreator<?, ?> messageCreator) {
Assert.notNull(messageCreator, "messageCreator must not be null");
this.messageCreator = messageCreator;
@@ -63,30 +77,38 @@ public class MessagingGateway extends RequestReplyTemplate {
this.messageMapper = messageMapper;
}
protected RequestReplyTemplate getRequestReplyTemplate() {
return this.requestReplyTemplate;
}
public void send(Object object) {
Message<?> message = (object instanceof Message) ? (Message) object :
this.messageCreator.createMessage(object);
if (message != null) {
this.send(message);
this.requestReplyTemplate.send(message);
}
}
public Object invoke() {
Message<?> message = this.receive();
public Object receive() {
Message<?> message = this.requestReplyTemplate.receive();
return (message != null) ? this.messageMapper.mapMessage(message) : null;
}
public Object invoke(Object object) {
return this.invoke(object, true);
public Object sendAndReceive(Object object) {
return this.sendAndReceive(object, true);
}
public Object invoke(Object object, boolean shouldMapMessage) {
public Message<?> sendAndReceiveMessage(Object object) {
return (Message<?>) this.sendAndReceive(object, false);
}
private Object sendAndReceive(Object object, boolean shouldMapMessage) {
Message<?> request = (object instanceof Message) ? (Message) object :
this.messageCreator.createMessage(object);
if (request == null) {
return null;
}
Message<?> reply = this.request(request);
Message<?> reply = this.requestReplyTemplate.request(request);
if (!shouldMapMessage) {
return reply;
}

View File

@@ -21,7 +21,7 @@ package org.springframework.integration.message;
*
* @author Mark Fisher
*/
public interface BlockingSource<T> extends PollableSource<T> {
public interface BlockingSource<T> extends Source<T> {
/**
* Receive a message, blocking indefinitely if necessary.

View File

@@ -1,31 +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.message;
/**
* Interface for any external message source that can be polled.
*
* @author Mark Fisher
*/
public interface PollableSource<T> extends Source {
/**
* Retrieve a message from this source or <code>null</code> if no message is available.
*/
Message<T> receive();
}

View File

@@ -21,6 +21,11 @@ package org.springframework.integration.message;
*
* @author Mark Fisher
*/
public interface Source {
public interface Source<T> {
/**
* Retrieve a message from this source or <code>null</code> if no message is available.
*/
Message<T> receive();
}

View File

@@ -17,11 +17,11 @@
package org.springframework.integration.message;
/**
* Interface for any message source that accepts subscribers.
* Interface for any component that accepts subscribers.
*
* @author Mark Fisher
*/
public interface SubscribableSource extends Source {
public interface Subscribable {
/**
* Register a {@link Target} as a subscriber to this source.

View File

@@ -25,6 +25,7 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.channel.DispatcherPolicy;
@@ -38,7 +39,7 @@ import org.springframework.integration.message.ErrorMessage;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.MessageDeliveryException;
import org.springframework.integration.message.PollableSource;
import org.springframework.integration.message.Source;
import org.springframework.integration.message.StringMessage;
import org.springframework.integration.scheduling.PollingSchedule;
import org.springframework.integration.scheduling.Subscription;
@@ -219,9 +220,7 @@ public class MessageBusTests {
@Test(expected = BeanCreationException.class)
public void testMultipleMessageBusBeans() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("multipleMessageBusBeans.xml",
this.getClass());
new ClassPathXmlApplicationContext("multipleMessageBusBeans.xml", this.getClass());
}
@Test
@@ -258,7 +257,7 @@ public class MessageBusTests {
assertTrue(messageBusAwareBean.getMessageBus() == context.getBean("bus"));
}
private static class FailingSource implements PollableSource<Object> {
private static class FailingSource implements Source<Object> {
private CountDownLatch latch;

View File

@@ -29,7 +29,7 @@ import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.PollableSource;
import org.springframework.integration.message.Source;
import org.springframework.integration.message.StringMessage;
import org.springframework.integration.message.Target;
@@ -96,7 +96,7 @@ public class SynchronousChannelTests {
@Test
public void testReceive() {
SynchronousChannel channel = new SynchronousChannel(new PollableSource<String>() {
SynchronousChannel channel = new SynchronousChannel(new Source<String>() {
public Message<String> receive() {
return new StringMessage("foo");
}
@@ -175,7 +175,7 @@ public class SynchronousChannelTests {
}
private static class MessageReturningTestSource implements PollableSource<String> {
private static class MessageReturningTestSource implements Source<String> {
private final String messageText;

View File

@@ -35,7 +35,7 @@ import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.PollableSource;
import org.springframework.integration.message.Source;
import org.springframework.integration.scheduling.PollingSchedule;
/**
@@ -429,7 +429,7 @@ public class PollingSourceEndpointTests {
}
private static class TestSource implements PollableSource<String> {
private static class TestSource implements Source<String> {
private String message;

View File

@@ -37,8 +37,8 @@ public class GatewayProxyFactoryBeanTests {
final MessageChannel requestChannel = new QueueChannel();
startResponder(requestChannel);
GatewayProxyFactoryBean proxyFactory = new GatewayProxyFactoryBean();
proxyFactory.setServiceInterface(TestService.class);
proxyFactory.setRequestChannel(requestChannel);
proxyFactory.setServiceInterface(TestService.class);
proxyFactory.afterPropertiesSet();
TestService service = (TestService) proxyFactory.getObject();
String result = service.requestReply("foo");