Refactored DefaultMessageDispatcher to delegate to MessageDistributor with logic previously in the DispatcherTask. The DispatcherTask is now an inner class of DefaultMessageDispatcher. Also added ChannelPurger (INT-105), MessageSelectingInterceptor (INT-98), and support for "datatype channels" (INT-99).

This commit is contained in:
Mark Fisher
2008-02-10 00:06:09 +00:00
parent d089567e6c
commit 405311d9b9
25 changed files with 751 additions and 202 deletions

View File

@@ -36,7 +36,7 @@ import org.springframework.integration.channel.DefaultChannelRegistry;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.channel.SimpleChannel;
import org.springframework.integration.dispatcher.DefaultMessageDispatcher;
import org.springframework.integration.dispatcher.MessageDispatcher;
import org.springframework.integration.dispatcher.SchedulingMessageDispatcher;
import org.springframework.integration.endpoint.ConcurrencyPolicy;
import org.springframework.integration.endpoint.DefaultMessageEndpoint;
import org.springframework.integration.endpoint.MessageEndpoint;
@@ -63,7 +63,7 @@ public class MessageBus implements ChannelRegistry, ApplicationContextAware, Lif
private Map<String, MessageEndpoint> endpoints = new ConcurrentHashMap<String, MessageEndpoint>();
private Map<MessageChannel, MessageDispatcher> dispatchers = new ConcurrentHashMap<MessageChannel, MessageDispatcher>();
private Map<MessageChannel, SchedulingMessageDispatcher> dispatchers = new ConcurrentHashMap<MessageChannel, SchedulingMessageDispatcher>();
private List<Lifecycle> lifecycleSourceAdapters = new CopyOnWriteArrayList<Lifecycle>();
@@ -194,7 +194,7 @@ public class MessageBus implements ChannelRegistry, ApplicationContextAware, Lif
public MessageChannel unregisterChannel(String name) {
MessageChannel removedChannel = this.channelRegistry.unregisterChannel(name);
if (removedChannel != null) {
MessageDispatcher removedDispatcher = this.dispatchers.remove(removedChannel);
SchedulingMessageDispatcher removedDispatcher = this.dispatchers.remove(removedChannel);
if (removedDispatcher != null && removedDispatcher.isRunning()) {
removedDispatcher.stop();
}
@@ -300,7 +300,7 @@ public class MessageBus implements ChannelRegistry, ApplicationContextAware, Lif
}
private void registerWithDispatcher(MessageChannel channel, MessageHandler handler, Schedule schedule) {
MessageDispatcher dispatcher = dispatchers.get(channel);
SchedulingMessageDispatcher dispatcher = dispatchers.get(channel);
if (dispatcher == null) {
if (logger.isWarnEnabled()) {
logger.warn("no dispatcher available for channel '" + channel.getName() + "', be sure to register the channel");
@@ -329,7 +329,7 @@ public class MessageBus implements ChannelRegistry, ApplicationContextAware, Lif
synchronized (this.lifecycleMonitor) {
this.activateEndpoints();
this.taskScheduler.start();
for (MessageDispatcher dispatcher : this.dispatchers.values()) {
for (SchedulingMessageDispatcher dispatcher : this.dispatchers.values()) {
dispatcher.start();
if (logger.isInfoEnabled()) {
logger.info("started dispatcher '" + dispatcher + "'");
@@ -362,7 +362,7 @@ public class MessageBus implements ChannelRegistry, ApplicationContextAware, Lif
logger.info("stopped source adapter '" + adapter + "'");
}
}
for (MessageDispatcher dispatcher : this.dispatchers.values()) {
for (SchedulingMessageDispatcher dispatcher : this.dispatchers.values()) {
dispatcher.stop();
if (logger.isInfoEnabled()) {
logger.info("stopped dispatcher '" + dispatcher + "'");

View File

@@ -27,12 +27,12 @@ import org.springframework.integration.message.Message;
*/
public interface ChannelInterceptor {
boolean preSend(Message message, MessageChannel channel);
boolean preSend(Message<?> message, MessageChannel channel);
void postSend(Message message, MessageChannel channel, boolean sent);
void postSend(Message<?> message, MessageChannel channel, boolean sent);
boolean preReceive(MessageChannel channel);
void postReceive(Message message, MessageChannel channel);
void postReceive(Message<?> message, MessageChannel channel);
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2002-2007 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.Message;
import org.springframework.integration.message.selector.MessageSelector;
/**
* A utility class for purging {@link Message Messages} from a
* {@link MessageChannel}. Any message that does <em>not</em> match the
* provided {@link MessageSelector} will be removed from the channel. If no
* {@link MessageSelector} is provided, then <em>all</em> messages will be
* cleared from the channel.
* <p>
* Note that the {@link #purge()} method operates on a snapshot of the messages
* within a channel at the time that the method is invoked. It is therefore
* possible that new messages will arrive on the channel during the purge
* operation and thus will <em>not</em> be removed. Likewise, messages to be
* purged may have been removed from the channel while the operation is taking
* place. Such messages will not be included in the returned list.
*
* @author Mark Fisher
*/
public class ChannelPurger {
private MessageChannel channel;
private MessageSelector selector;
public ChannelPurger(MessageChannel channel) {
this.channel = channel;
}
public ChannelPurger(MessageChannel channel, MessageSelector selector) {
this(channel);
this.selector = selector;
}
public final List<Message<?>> purge() {
if (this.selector == null) {
return this.channel.clear();
}
return this.channel.purge(this.selector);
}
}

View File

@@ -20,6 +20,7 @@ import java.util.List;
import org.springframework.integration.dispatcher.DispatcherPolicy;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.selector.MessageSelector;
/**
* Base channel interface defining common behavior for message sending and receiving.
@@ -88,11 +89,11 @@ public interface MessageChannel {
/**
* Remove all {@link Message Messages} from this channel.
*/
List<Message> clear();
List<Message<?>> clear();
/**
* Remove any expired {@link Message Messages} from this channel.
* Remove any {@link Message Messages} that are not accepted by the provided selector.
*/
List<Message> purge();
List<Message<?>> purge(MessageSelector selector);
}

View File

@@ -25,6 +25,7 @@ import java.util.concurrent.TimeUnit;
import org.springframework.integration.dispatcher.DispatcherPolicy;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.selector.MessageSelector;
import org.springframework.util.Assert;
/**
@@ -111,20 +112,21 @@ public class SimpleChannel extends AbstractMessageChannel {
}
}
public List<Message> clear() {
List<Message> clearedMessages = new ArrayList<Message>();
public List<Message<?>> clear() {
List<Message<?>> clearedMessages = new ArrayList<Message<?>>();
this.queue.drainTo(clearedMessages);
return clearedMessages;
}
public List<Message> purge() {
List<Message> purgedMessages = new ArrayList<Message>();
// take a snapshot
public List<Message<?>> purge(MessageSelector selector) {
if (selector == null) {
return this.clear();
}
List<Message<?>> purgedMessages = new ArrayList<Message<?>>();
Object[] array = this.queue.toArray();
for (Object o : array) {
Message message = (Message) o;
if (message.isExpired() && this.queue.remove(message)) {
// message was still in the queue
Message<?> message = (Message<?>) o;
if (!selector.accept(message) && this.queue.remove(message)) {
purgedMessages.add(message);
}
}

View File

@@ -14,8 +14,10 @@
* limitations under the License.
*/
package org.springframework.integration.channel;
package org.springframework.integration.channel.interceptor;
import org.springframework.integration.channel.ChannelInterceptor;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.message.Message;
/**
@@ -26,18 +28,18 @@ import org.springframework.integration.message.Message;
*/
public class ChannelInterceptorAdapter implements ChannelInterceptor {
public boolean preSend(Message message, MessageChannel channel) {
public boolean preSend(Message<?> message, MessageChannel channel) {
return true;
}
public void postSend(Message message, MessageChannel channel, boolean sent) {
public void postSend(Message<?> message, MessageChannel channel, boolean sent) {
}
public boolean preReceive(MessageChannel channel) {
return true;
}
public void postReceive(Message message, MessageChannel channel) {
public void postReceive(Message<?> message, MessageChannel channel) {
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2002-2007 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.interceptor;
import java.util.Arrays;
import java.util.List;
import org.springframework.integration.MessageDeliveryException;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.selector.MessageSelector;
/**
* A {@link org.springframework.integration.channel.ChannelInterceptor} that
* delegates to a list of {@link MessageSelector MessageSelectors} to decide
* whether a {@link Message} should be accepted on the {@link MessageChannel}.
*
* @author Mark Fisher
*/
public class MessageSelectingInterceptor extends ChannelInterceptorAdapter {
private final List<MessageSelector> selectors;
public MessageSelectingInterceptor(MessageSelector... selectors) {
this.selectors = Arrays.asList(selectors);
}
@Override
public boolean preSend(Message<?> message, MessageChannel channel) {
for (MessageSelector selector : this.selectors) {
if (!selector.accept(message)) {
throw new MessageDeliveryException(
"selector '" + selector + "' did not accept message '" + message + "'");
}
}
return true;
}
}

View File

@@ -21,12 +21,18 @@ import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.channel.SimpleChannel;
import org.springframework.integration.channel.interceptor.MessageSelectingInterceptor;
import org.springframework.integration.dispatcher.DispatcherPolicy;
import org.springframework.integration.message.selector.MessageSelector;
import org.springframework.integration.message.selector.PayloadTypeSelector;
import org.springframework.util.StringUtils;
/**
@@ -44,6 +50,10 @@ public class ChannelParser implements BeanDefinitionParser {
private static final String DISPATCHER_POLICY_ELEMENT = "dispatcher-policy";
private static final String DATATYPE_ATTRIBUTE = "datatype";
private static final String INTERCEPTORS_PROPERTY = "interceptors";
public BeanDefinition parse(Element element, ParserContext parserContext) {
RootBeanDefinition channelDef = new RootBeanDefinition(SimpleChannel.class);
@@ -64,6 +74,24 @@ public class ChannelParser implements BeanDefinitionParser {
int capacity = (StringUtils.hasText(capAttr)) ? Integer.parseInt(capAttr) : SimpleChannel.DEFAULT_CAPACITY;
channelDef.getConstructorArgumentValues().addIndexedArgumentValue(0, capacity);
channelDef.getConstructorArgumentValues().addIndexedArgumentValue(1, dispatcherPolicy);
ManagedList interceptors = new ManagedList();
String datatypeAttr = element.getAttribute(DATATYPE_ATTRIBUTE);
if (StringUtils.hasText(datatypeAttr)) {
String[] datatypes = StringUtils.commaDelimitedListToStringArray(datatypeAttr);
RootBeanDefinition selectorDef = new RootBeanDefinition(PayloadTypeSelector.class);
selectorDef.getConstructorArgumentValues().addGenericArgumentValue(datatypes);
String selectorBeanName = parserContext.getReaderContext().generateBeanName(selectorDef);
BeanComponentDefinition selectorComponent = new BeanComponentDefinition(selectorDef, selectorBeanName);
parserContext.registerBeanComponent(selectorComponent);
RootBeanDefinition interceptorDef = new RootBeanDefinition(MessageSelectingInterceptor.class);
interceptorDef.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference(selectorBeanName));
String interceptorBeanName = parserContext.getReaderContext().generateBeanName(interceptorDef);
BeanComponentDefinition interceptorComponent = new BeanComponentDefinition(interceptorDef, interceptorBeanName);
parserContext.registerBeanComponent(interceptorComponent);
interceptors.add(new RuntimeBeanReference(interceptorBeanName));
}
// TODO: parse interceptor sub-elements
channelDef.getPropertyValues().addPropertyValue(INTERCEPTORS_PROPERTY, interceptors);
String beanName = element.getAttribute(ID_ATTRIBUTE);
parserContext.registerBeanComponent(new BeanComponentDefinition(channelDef, beanName));
return channelDef;

View File

@@ -53,6 +53,7 @@
<xsd:attribute name="id" type="xsd:ID" use="required"/>
<xsd:attribute name="capacity" type="xsd:integer"/>
<xsd:attribute name="publish-subscribe" type="xsd:boolean" default="false"/>
<xsd:attribute name="datatype" type="xsd:string"/>
</xsd:complexType>
</xsd:element>

View File

@@ -16,11 +16,12 @@
package org.springframework.integration.dispatcher;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -28,6 +29,8 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.context.Lifecycle;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.message.Message;
import org.springframework.integration.scheduling.MessagingTask;
import org.springframework.integration.scheduling.MessagingTaskScheduler;
import org.springframework.integration.scheduling.MessagingTaskSchedulerAware;
import org.springframework.integration.scheduling.PollingSchedule;
@@ -44,11 +47,13 @@ import org.springframework.util.Assert;
*
* @author Mark Fisher
*/
public class DefaultMessageDispatcher implements MessageDispatcher, MessagingTaskSchedulerAware {
public class DefaultMessageDispatcher implements SchedulingMessageDispatcher, MessagingTaskSchedulerAware {
protected Log logger = LogFactory.getLog(this.getClass());
private MessageChannel channel;
private final MessageChannel channel;
private final MessageRetriever retriever;
private MessagingTaskScheduler scheduler;
@@ -56,7 +61,7 @@ public class DefaultMessageDispatcher implements MessageDispatcher, MessagingTas
private Map<Schedule, List<MessageHandler>> scheduledHandlers = new ConcurrentHashMap<Schedule, List<MessageHandler>>();
private List<ScheduledFuture<?>> futures = new CopyOnWriteArrayList<ScheduledFuture<?>>();
private AtomicLong totalMessagesProcessed = new AtomicLong();
private volatile boolean running;
@@ -66,6 +71,7 @@ public class DefaultMessageDispatcher implements MessageDispatcher, MessagingTas
public DefaultMessageDispatcher(MessageChannel channel) {
Assert.notNull(channel, "'channel' must not be null");
this.channel = channel;
this.retriever = new ChannelPollingMessageRetriever(this.channel);
}
@@ -127,21 +133,14 @@ public class DefaultMessageDispatcher implements MessageDispatcher, MessagingTas
return;
}
synchronized (this.lifecycleMonitor) {
for (Map.Entry<Schedule, List<MessageHandler>> entry : this.scheduledHandlers.entrySet()) {
Schedule schedule = entry.getKey();
List<MessageHandler> handlers = entry.getValue();
DispatcherTask task = new DispatcherTask(channel);
task.setSchedule(schedule);
for (Schedule schedule : this.scheduledHandlers.keySet()) {
List<MessageHandler> handlers = this.scheduledHandlers.get(schedule);
for (MessageHandler handler : handlers) {
if (handler instanceof Lifecycle) {
((Lifecycle) handler).start();
}
task.addHandler(handler);
}
ScheduledFuture<?> future = this.scheduler.schedule(task);
if (future != null) {
futures.add(future);
}
this.scheduler.schedule(new DispatcherTask(schedule));
}
this.running = true;
}
@@ -152,13 +151,10 @@ public class DefaultMessageDispatcher implements MessageDispatcher, MessagingTas
return;
}
synchronized (this.lifecycleMonitor) {
for (ScheduledFuture<?> future : this.futures) {
future.cancel(true);
for (List<MessageHandler> handlerList : scheduledHandlers.values()) {
for (MessageHandler handler : handlerList) {
if (handler instanceof Lifecycle) {
((Lifecycle) handler).stop();
}
for (List<MessageHandler> handlerList : scheduledHandlers.values()) {
for (MessageHandler handler : handlerList) {
if (handler instanceof Lifecycle) {
((Lifecycle) handler).stop();
}
}
}
@@ -166,4 +162,57 @@ public class DefaultMessageDispatcher implements MessageDispatcher, MessagingTas
}
}
public int dispatch() {
MessageDistributor distributor = this.getDistributor(this.defaultSchedule);
return this.doDispatch(distributor);
}
private int doDispatch(MessageDistributor distributor) {
int messagesProcessed = 0;
Collection<Message<?>> messages = this.retriever.retrieveMessages();
if (messages == null) {
return 0;
}
for (Message<?> message : messages) {
if (distributor.distribute(message)) {
messagesProcessed++;
}
}
totalMessagesProcessed.addAndGet(messagesProcessed);
return messagesProcessed;
}
private MessageDistributor getDistributor(Schedule schedule) {
if (schedule == null) {
schedule = this.defaultSchedule;
}
MessageDistributor distributor = new DefaultMessageDistributor(this.channel.getDispatcherPolicy());
for (MessageHandler handler : this.scheduledHandlers.get(schedule)) {
distributor.addHandler(handler);
}
return distributor;
}
private class DispatcherTask implements MessagingTask {
private Schedule schedule;
private MessageDistributor distributor;
public DispatcherTask(Schedule schedule) {
this.schedule = (schedule != null) ? schedule : defaultSchedule;
this.distributor = getDistributor(this.schedule);
}
public Schedule getSchedule() {
return this.schedule;
}
public void run() {
doDispatch(this.distributor);
}
}
}

View File

@@ -17,7 +17,6 @@
package org.springframework.integration.dispatcher;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -27,87 +26,44 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.integration.MessageDeliveryException;
import org.springframework.integration.MessageHandlingException;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.handler.MessageHandlerNotRunningException;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.selector.MessageSelectorRejectedException;
import org.springframework.integration.scheduling.MessagingTask;
import org.springframework.integration.scheduling.Schedule;
import org.springframework.util.Assert;
/**
* A task for polling {@link MessageDispatcher MessageDispatchers}. If
* {@link #broadcast} is set to <code>false</code> (the default), each message
* will be sent to a single {@link MessageHandler}. Otherwise, each
* retrieved {@link Message} will be sent to all of the handlers.
* Default implementation of the {@link MessageDistributor} interface.
*
* @author Mark Fisher
*/
public class DispatcherTask implements MessagingTask {
public class DefaultMessageDistributor implements MessageDistributor {
private Log logger = LogFactory.getLog(this.getClass());
private final Log logger = LogFactory.getLog(this.getClass());
private Schedule schedule;
private final List<MessageHandler> handlers = new CopyOnWriteArrayList<MessageHandler>();
private DispatcherPolicy dispatcherPolicy = new DispatcherPolicy();
private MessageRetriever retriever;
private List<MessageHandler> handlers = new CopyOnWriteArrayList<MessageHandler>();
private final DispatcherPolicy dispatcherPolicy;
public DispatcherTask(MessageChannel channel) {
Assert.notNull(channel, "'channel' must not be null");
this.retriever = new ChannelPollingMessageRetriever(channel);
DispatcherPolicy dispatcherPolicy = channel.getDispatcherPolicy();
if (dispatcherPolicy != null) {
this.dispatcherPolicy = dispatcherPolicy;
}
public DefaultMessageDistributor(DispatcherPolicy dispatcherPolicy) {
Assert.notNull(dispatcherPolicy, "'dispatcherPolicy' must not be null");
this.dispatcherPolicy = dispatcherPolicy;
}
public void setSchedule(Schedule schedule) {
Assert.notNull(schedule, "'schedule' must not be null");
this.schedule = schedule;
}
public Schedule getSchedule() {
return this.schedule;
}
public void addHandler(MessageHandler handler) {
Assert.notNull(handler, "'handler' must not be null");
this.handlers.add(handler);
}
/**
* Retrieves messages and dispatches to the executors.
*
* @return the number of messages processed
*/
public int dispatch() {
int messagesProcessed = 0;
Collection<Message<?>> messages = this.retriever.retrieveMessages();
if (messages == null) {
return 0;
}
for (Message<?> message : messages) {
if (dispatchMessage(message)) {
messagesProcessed++;
}
}
return messagesProcessed;
}
protected boolean dispatchMessage(Message<?> message) {
public boolean distribute(Message<?> message) {
int attempts = 0;
List<MessageHandler> targets = new ArrayList<MessageHandler>(this.handlers);
while (attempts < this.dispatcherPolicy.getRejectionLimit()) {
if (attempts > 0) {
if (logger.isDebugEnabled()) {
logger.debug("handler(s) rejected message after " + attempts
+ " attempt(s), will try again after 'retryInterval' of " +
logger.debug("handler(s) rejected message after " + attempts +
" attempt(s), will try again after 'retryInterval' of " +
this.dispatcherPolicy.getRetryInterval() + " milliseconds");
}
try {
@@ -164,8 +120,4 @@ public class DispatcherTask implements MessagingTask {
return false;
}
public void run() {
this.dispatch();
}
}

View File

@@ -16,19 +16,17 @@
package org.springframework.integration.dispatcher;
import org.springframework.context.Lifecycle;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.scheduling.Schedule;
/**
* Strategy interface for dispatching messages.
*
* @author Mark Fisher
*/
public interface MessageDispatcher extends Lifecycle {
public interface MessageDispatcher {
void addHandler(MessageHandler handler);
void addHandler(MessageHandler handler, Schedule schedule);
int dispatch();
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2002-2007 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.dispatcher;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.message.Message;
/**
* Strategy interface for distributing a {@link Message} to one or more
* {@link MessageHandler MessageHandlers}.
*
* @author Mark Fisher
*/
public interface MessageDistributor {
void addHandler(MessageHandler handler);
boolean distribute(Message<?> message);
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2002-2007 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.dispatcher;
import org.springframework.context.Lifecycle;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.scheduling.Schedule;
/**
* An extension to the {@link MessageDispatcher} strategy for handlers that may
* be scheduled.
*
* @author Mark Fisher
*/
public interface SchedulingMessageDispatcher extends MessageDispatcher, Lifecycle {
void setDefaultSchedule(Schedule defaultSchedule);
void addHandler(MessageHandler handler, Schedule schedule);
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2002-2007 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.selector;
import org.springframework.integration.message.Message;
/**
* A {@link MessageSelector} that accepts {@link Message Messages} that are
* <em>not</em> expired.
*
* @author Mark Fisher
*/
public class UnexpiredMessageSelector implements MessageSelector {
public boolean accept(Message<?> message) {
return (!message.isExpired());
}
}