INT-1257, INT-1263 Refactoring Message History (work in progress): MessageHistoryWriter's writeHistory method is now static. Added HistoryProvider interface and MessageHistoryBeanPostProcessor.

This commit is contained in:
Mark Fisher
2010-08-25 18:53:56 +00:00
parent 97c292cc56
commit f5f948da4c
23 changed files with 192 additions and 206 deletions

View File

@@ -23,12 +23,15 @@ import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.OrderComparator;
import org.springframework.core.convert.ConversionService;
import org.springframework.integration.Message;
import org.springframework.integration.MessageDeliveryException;
import org.springframework.integration.MessagingException;
import org.springframework.integration.context.HistoryProvider;
import org.springframework.integration.context.IntegrationObjectSupport;
import org.springframework.integration.context.MessageHistoryWriter;
import org.springframework.integration.core.MessageBuilder;
import org.springframework.integration.core.MessageChannel;
import org.springframework.util.Assert;
@@ -43,10 +46,12 @@ import org.springframework.util.StringUtils;
* @author Mark Fisher
* @author Oleg Zhurakousky
*/
public abstract class AbstractMessageChannel extends IntegrationObjectSupport implements MessageChannel {
public abstract class AbstractMessageChannel extends IntegrationObjectSupport implements MessageChannel, HistoryProvider {
private final Log logger = LogFactory.getLog(this.getClass());
private volatile boolean shouldIncludeInHistory = false;
private final AtomicLong sendSuccessCount = new AtomicLong();
private final AtomicLong sendErrorCount = new AtomicLong();
@@ -54,11 +59,16 @@ public abstract class AbstractMessageChannel extends IntegrationObjectSupport im
private volatile Class<?>[] datatypes = new Class<?>[] { Object.class };
private final ChannelInterceptorList interceptors = new ChannelInterceptorList();
public String getComponentType(){
public String getComponentType() {
return "channel";
}
public void setShouldIncludeInHistory(boolean shouldIncludeInHistory) {
this.shouldIncludeInHistory = shouldIncludeInHistory;
}
/**
* Return the current count of Messages that have been sent
* to this channel successfully.
@@ -157,9 +167,11 @@ public abstract class AbstractMessageChannel extends IntegrationObjectSupport im
* time or the sending thread is interrupted.
*/
public final boolean send(Message<?> message, long timeout) {
this.writeMessageHistory(message);
Assert.notNull(message, "message must not be null");
Assert.notNull(message.getPayload(), "message payload must not be null");
if (this.shouldIncludeInHistory) {
message = MessageHistoryWriter.writeHistory(this, message);
}
message = this.convertPayloadIfNecessary(message);
message = this.interceptors.preSend(message, this);
if (message == null) {

View File

@@ -16,20 +16,15 @@
package org.springframework.integration.config;
import java.util.Map;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.SmartLifecycle;
import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.integration.context.IntegrationObjectSupport;
import org.springframework.integration.context.MessageHistoryWriter;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.core.MessageHandler;
import org.springframework.integration.core.PollableChannel;
@@ -44,7 +39,7 @@ import org.springframework.util.StringUtils;
/**
* @author Mark Fisher
* @author Oleg Zhurakousky
* @author Josh Long
* @author Josh Long
*/
public class ConsumerEndpointFactoryBean
implements FactoryBean<AbstractEndpoint>, BeanFactoryAware, BeanNameAware, InitializingBean, SmartLifecycle {
@@ -59,9 +54,9 @@ public class ConsumerEndpointFactoryBean
private volatile boolean autoStartup = true;
private volatile MessageChannel inputChannel;
private volatile MessageChannel inputChannel;
private volatile ConfigurableBeanFactory beanFactory;
private volatile ConfigurableBeanFactory beanFactory;
private volatile AbstractEndpoint endpoint;
@@ -71,6 +66,7 @@ public class ConsumerEndpointFactoryBean
private final Object handlerMonitor = new Object();
public void setHandler(MessageHandler handler) {
Assert.notNull(handler, "handler must not be null");
synchronized (this.handlerMonitor) {
@@ -79,9 +75,9 @@ public class ConsumerEndpointFactoryBean
}
}
public void setInputChannel(MessageChannel inputChannel) {
this.inputChannel= inputChannel;
}
public void setInputChannel(MessageChannel inputChannel) {
this.inputChannel = inputChannel;
}
public void setInputChannelName(String inputChannelName) {
this.inputChannelName = inputChannelName;
@@ -100,22 +96,14 @@ public class ConsumerEndpointFactoryBean
}
public void setBeanFactory(BeanFactory beanFactory) {
Assert.isInstanceOf(ConfigurableBeanFactory.class, beanFactory,
"a ConfigurableBeanFactory is required");
Assert.isInstanceOf(ConfigurableBeanFactory.class, beanFactory, "a ConfigurableBeanFactory is required");
this.beanFactory = (ConfigurableBeanFactory) beanFactory;
}
public void afterPropertiesSet() throws Exception {
// Will check if this.handler needs to be wrapped in a MessageHistoryAwareMessageHandler.
// Such wrapping is only required if this.beanFactory contains a bean of type MessageHistoryWriter.
Map<String, MessageHistoryWriter> historyWriters = BeanFactoryUtils.beansOfTypeIncludingAncestors(
(ListableBeanFactory) this.beanFactory, MessageHistoryWriter.class);
if (historyWriters.size() == 1) {
MessageHistoryWriter writer = historyWriters.values().iterator().next();
if (!this.beanName.startsWith("org.springframework") && this.handler instanceof IntegrationObjectSupport) {
this.handler = new MessageHistoryWritingMessageHandler(this.handler, writer, this.beanName);
}
}
if (!this.beanName.startsWith("org.springframework") && this.handler instanceof IntegrationObjectSupport) {
((IntegrationObjectSupport) this.handler).setComponentName(this.beanName);
}
this.initializeEndpoint();
}
@@ -142,34 +130,27 @@ public class ConsumerEndpointFactoryBean
if (this.initialized) {
return;
}
MessageChannel channel = null;
if(StringUtils.hasText(this.inputChannelName)) {
Assert.isTrue(this.beanFactory.containsBean(this.inputChannelName),
"no such input channel '" + this.inputChannelName + "' for endpoint '" + this.beanName + "'");
channel = this.beanFactory.getBean(this.inputChannelName, MessageChannel.class);
}
if( this.inputChannel != null ){
channel = this.inputChannel;
}
Assert.state( channel != null , "one of inputChannelName or inputChannel is required");
MessageChannel channel = null;
if (StringUtils.hasText(this.inputChannelName)) {
Assert.isTrue(this.beanFactory.containsBean(this.inputChannelName), "no such input channel '"
+ this.inputChannelName + "' for endpoint '" + this.beanName + "'");
channel = this.beanFactory.getBean(this.inputChannelName, MessageChannel.class);
}
if (this.inputChannel != null) {
channel = this.inputChannel;
}
Assert.state(channel != null, "one of inputChannelName or inputChannel is required");
if (channel instanceof SubscribableChannel) {
Assert.isNull(this.pollerMetadata, "A poller should not be specified for endpoint '" + this.beanName
+ "', since '" + channel + "' is a SubscribableChannel (not pollable).");
this.endpoint = new EventDrivenConsumer((SubscribableChannel) channel, this.handler);
}
else if (channel instanceof PollableChannel) {
PollingConsumer pollingConsumer = new PollingConsumer(
(PollableChannel) channel, this.handler);
PollingConsumer pollingConsumer = new PollingConsumer((PollableChannel) channel, this.handler);
if (this.pollerMetadata == null) {
this.pollerMetadata = IntegrationContextUtils.getDefaultPollerMetadata(this.beanFactory);
Assert.notNull(this.pollerMetadata, "No poller has been defined for endpoint '"
+ this.beanName + "', and no default poller is available within the context.");
Assert.notNull(this.pollerMetadata, "No poller has been defined for endpoint '" + this.beanName
+ "', and no default poller is available within the context.");
}
pollingConsumer.setTrigger(this.pollerMetadata.getTrigger());
pollingConsumer.setMaxMessagesPerPoll(this.pollerMetadata.getMaxMessagesPerPoll());
@@ -181,8 +162,7 @@ public class ConsumerEndpointFactoryBean
this.endpoint = pollingConsumer;
}
else {
throw new IllegalArgumentException(
"unsupported channel type: [" + channel.getClass() + "]");
throw new IllegalArgumentException("unsupported channel type: [" + channel.getClass() + "]");
}
this.endpoint.setBeanName(this.beanName);
this.endpoint.setBeanFactory(this.beanFactory);
@@ -192,6 +172,7 @@ public class ConsumerEndpointFactoryBean
}
}
/*
* SmartLifecycle implementation (delegates to the created endpoint)
*/

View File

@@ -1,81 +0,0 @@
/*
* Copyright 2002-2010 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.core.Ordered;
import org.springframework.integration.Message;
import org.springframework.integration.context.MessageHistoryWriter;
import org.springframework.integration.context.NamedComponent;
import org.springframework.integration.core.MessageHandler;
import org.springframework.util.Assert;
/**
* Wrapper class to be used when a particular MessageHandler needs to be tracked in MessageHistory.
* Note, any MessageHandler that is wrapped by this class will be tracked in MessageHistory
* only when a MessageHistoryWriter is present in the ApplicationContext.
*
* @author Oleg Zhurakousky
* @author Mark Fisher
* @since 2.0
*/
class MessageHistoryWritingMessageHandler implements NamedComponent, MessageHandler, Ordered {
private final MessageHandler targetHandler;
private final MessageHistoryWriter historyWriter;
private final String componentName;
/**
* @param historyWriter
* @param endpointName
* @param targetHandler
*/
public MessageHistoryWritingMessageHandler(MessageHandler targetHandler, MessageHistoryWriter historyWriter, String endpointName) {
Assert.notNull(targetHandler, "targetHandler must not be null");
Assert.notNull(historyWriter, "historyWriter must not be null");
this.targetHandler = targetHandler;
this.historyWriter = historyWriter;
this.componentName = endpointName;
}
public String getComponentName() {
return this.componentName;
}
public String getComponentType() {
return (targetHandler instanceof NamedComponent) ? ((NamedComponent) targetHandler).getComponentType() : null;
}
public int getOrder() {
return (targetHandler instanceof Ordered) ? ((Ordered) targetHandler).getOrder() : Ordered.LOWEST_PRECEDENCE;
}
/**
* Writes the MessageHistory event and then invokes the target handler.
*/
public void handleMessage(Message<?> message) {
if (message != null) {
message = this.historyWriter.writeHistory(this, message);
}
this.targetHandler.handleMessage(message);
}
}

View File

@@ -13,38 +13,41 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.config.xml;
import org.w3c.dom.Element;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
/**
* @author Oleg Zhurakousky
* @author Mark Fisher
* @since 2.0
*/
public class MessageHistoryParser extends AbstractSimpleBeanDefinitionParser {
private String messageHistory;
private static final String POST_PROCESSOR_CLASSNAME = "org.springframework.integration.context.MessageHistoryBeanPostProcessor";
@Override
protected String getBeanClassName(Element element) {
return "org.springframework.integration.context.MessageHistoryWriter";
return POST_PROCESSOR_CLASSNAME;
}
@Override
protected boolean shouldGenerateId() {
return false;
}
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext){
if (messageHistory == null){
messageHistory = BeanDefinitionReaderUtils.generateBeanName(definition, parserContext.getRegistry());
} else {
throw new BeanDefinitionStoreException("Attempt to register more then one MessageHistoryWriter");
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) {
if (parserContext.getRegistry().containsBeanDefinition(POST_PROCESSOR_CLASSNAME)) {
throw new BeanDefinitionStoreException("At most one MessageHistoryBeanPostProcessor may be registered within a context.");
}
return messageHistory;
return POST_PROCESSOR_CLASSNAME;
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright 2002-2010 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.context;
/**
* @author Mark Fisher
* @since 2.0
*/
public interface HistoryProvider extends NamedComponent {
void setShouldIncludeInHistory(boolean shouldIncludeInHistory);
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.context;
import org.springframework.beans.factory.BeanFactory;
@@ -27,7 +28,6 @@ import org.springframework.scheduling.TaskScheduler;
import org.springframework.util.Assert;
/**
* Utility methods for accessing common integration components from the BeanFactory.
*

View File

@@ -21,13 +21,10 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.core.convert.ConversionService;
import org.springframework.integration.Message;
import org.springframework.integration.context.metadata.MetadataPersister;
import org.springframework.integration.context.metadata.PropertiesBasedMetadataPersister;
import org.springframework.scheduling.TaskScheduler;
@@ -54,8 +51,6 @@ public abstract class IntegrationObjectSupport implements BeanNameAware, NamedCo
*/
protected final Log logger = LogFactory.getLog(getClass());
private volatile MessageHistoryWriter historyWriter;
private volatile MetadataPersister<?> metadataPersister;
private volatile String beanName;
@@ -80,6 +75,7 @@ public abstract class IntegrationObjectSupport implements BeanNameAware, NamedCo
public final String getComponentName() {
return StringUtils.hasText(this.componentName) ? this.componentName : this.beanName;
}
/**
* Sets the name of this component.
*
@@ -111,11 +107,6 @@ public abstract class IntegrationObjectSupport implements BeanNameAware, NamedCo
}
throw new BeanInitializationException("failed to initialize", e);
}
if (this.beanFactory != null) {
if (BeanFactoryUtils.beansOfTypeIncludingAncestors((ListableBeanFactory)this.beanFactory, MessageHistoryWriter.class).size() == 1){
this.historyWriter = this.beanFactory.getBean(MessageHistoryWriter.class);
}
}
}
/**
@@ -181,11 +172,4 @@ public abstract class IntegrationObjectSupport implements BeanNameAware, NamedCo
return (this.beanName != null) ? this.beanName : super.toString();
}
protected <T> Message<T> writeMessageHistory(Message<T> message) {
if (historyWriter != null && message != null) {
return historyWriter.writeHistory(this, message);
}
return message;
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2002-2010 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.context;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* @author Mark Fisher
* @since 2.0
*/
//TODO: check name against pattern (include/exclude filters?), and check type as well?
public class MessageHistoryBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof HistoryProvider) {
((HistoryProvider) bean).setShouldIncludeInHistory(true);
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof HistoryProvider) {
((HistoryProvider) bean).setShouldIncludeInHistory(true);
}
return bean;
}
}

View File

@@ -20,18 +20,11 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.integration.Message;
import org.springframework.integration.MessageHeaders;
import org.springframework.integration.core.MessageBuilder;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.core.MessageHandler;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
@@ -43,7 +36,7 @@ import org.springframework.util.StringUtils;
* @author Mark Fisher
* @since 2.0
*/
public class MessageHistoryWriter implements BeanFactoryAware, InitializingBean {
public abstract class MessageHistoryWriter {
public static final String NAME_PROPERTY = "name";
@@ -52,22 +45,8 @@ public class MessageHistoryWriter implements BeanFactoryAware, InitializingBean
public static final String TIMESTAMP_PROPERTY = "timestamp";
private volatile BeanFactory beanFactory;
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.beanFactory, "BeanFactory is required");
if (BeanFactoryUtils.beansOfTypeIncludingAncestors((ListableBeanFactory) this.beanFactory, MessageHistoryWriter.class).size() > 1) {
throw new IllegalArgumentException("more than one MessageHistoryWriter exists in the context");
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
public <T> Message<T> writeHistory(NamedComponent component, Message<T> message) {
public static <T> Message<T> writeHistory(NamedComponent component, Message<T> message) {
if (component != null && message != null) {
String componentName = component.getComponentName();
if (componentName != null && !componentName.startsWith("org.springframework.integration")) {

View File

@@ -17,6 +17,7 @@
package org.springframework.integration.endpoint;
import org.springframework.integration.Message;
import org.springframework.integration.context.MessageHistoryWriter;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.core.MessageProducer;
import org.springframework.integration.core.MessagingTemplate;
@@ -50,7 +51,7 @@ public abstract class MessageProducerSupport extends AbstractEndpoint implements
protected void sendMessage(Message<?> message) {
if (message != null) {
message = this.writeMessageHistory(message);
message = MessageHistoryWriter.writeHistory(this, message);
}
this.messagingTemplate.send(this.outputChannel, message);
}

View File

@@ -27,8 +27,8 @@ import org.springframework.integration.core.MessagingTemplate;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.core.SubscribableChannel;
import org.springframework.integration.endpoint.AbstractEndpoint;
import org.springframework.integration.endpoint.PollingConsumer;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.endpoint.PollingConsumer;
import org.springframework.integration.handler.BridgeHandler;
import org.springframework.integration.mapping.InboundMessageMapper;
import org.springframework.scheduling.support.PeriodicTrigger;

View File

@@ -37,6 +37,7 @@ import org.springframework.expression.Expression;
import org.springframework.integration.Message;
import org.springframework.integration.annotation.Gateway;
import org.springframework.integration.context.BeanFactoryChannelResolver;
import org.springframework.integration.context.HistoryProvider;
import org.springframework.integration.context.IntegrationContextUtils;
import org.springframework.integration.core.ChannelResolver;
import org.springframework.integration.core.MessageChannel;
@@ -58,7 +59,7 @@ import org.springframework.util.StringUtils;
* @author Mark Fisher
* @author Oleg Zhurakousky
*/
public class GatewayProxyFactoryBean extends AbstractEndpoint implements FactoryBean<Object>, MethodInterceptor, BeanClassLoaderAware {
public class GatewayProxyFactoryBean extends AbstractEndpoint implements HistoryProvider, FactoryBean<Object>, MethodInterceptor, BeanClassLoaderAware {
private volatile InboundMessageMapper<Throwable> exceptionMapper;
@@ -74,6 +75,8 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint implements Factory
private volatile ChannelResolver channelResolver;
private volatile boolean shouldIncludeInHistory = false;
private volatile TypeConverter typeConverter = new SimpleTypeConverter();
private volatile ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
@@ -156,6 +159,10 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint implements Factory
this.defaultReplyTimeout = defaultReplyTimeout;
}
public void setShouldIncludeInHistory(boolean shouldIncludeInHistory) {
this.shouldIncludeInHistory = shouldIncludeInHistory;
}
public void setTypeConverter(TypeConverter typeConverter) {
Assert.notNull(typeConverter, "typeConverter must not be null");
this.typeConverter = typeConverter;
@@ -331,6 +338,9 @@ public class GatewayProxyFactoryBean extends AbstractEndpoint implements Factory
if (this.getBeanFactory() != null) {
gateway.setBeanFactory(this.getBeanFactory());
}
if (this.shouldIncludeInHistory) {
gateway.setShouldIncludeInHistory(this.shouldIncludeInHistory);
}
gateway.afterPropertiesSet();
return gateway;
}

View File

@@ -18,6 +18,8 @@ package org.springframework.integration.gateway;
import org.springframework.integration.Message;
import org.springframework.integration.MessagingException;
import org.springframework.integration.context.HistoryProvider;
import org.springframework.integration.context.MessageHistoryWriter;
import org.springframework.integration.mapping.InboundMessageMapper;
import org.springframework.integration.mapping.OutboundMessageMapper;
import org.springframework.util.Assert;
@@ -33,12 +35,14 @@ import org.springframework.util.Assert;
* @author Mark Fisher
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public class SimpleMessagingGateway extends AbstractMessagingGateway {
public class SimpleMessagingGateway extends AbstractMessagingGateway implements HistoryProvider {
private final InboundMessageMapper inboundMapper;
private final OutboundMessageMapper outboundMapper;
private volatile boolean shouldIncludeInHistory = false;
public SimpleMessagingGateway() {
SimpleMessageMapper mapper = new SimpleMessageMapper();
@@ -52,7 +56,12 @@ public class SimpleMessagingGateway extends AbstractMessagingGateway {
this.inboundMapper = inboundMapper;
this.outboundMapper = outboundMapper;
}
public void setShouldIncludeInHistory(boolean shouldIncludeInHistory) {
this.shouldIncludeInHistory = shouldIncludeInHistory;
}
public Message<?> sendAndReceiveMessage(Object object) {
return (Message<?>) super.sendAndReceive(object, false);
}
@@ -80,7 +89,9 @@ public class SimpleMessagingGateway extends AbstractMessagingGateway {
Message<?> message = null;
try {
message = this.inboundMapper.toMessage(object);
message = this.writeMessageHistory(message);
if (this.shouldIncludeInHistory) {
message = MessageHistoryWriter.writeHistory(this, message);
}
}
catch (Exception e) {
if (e instanceof RuntimeException) {
@@ -90,4 +101,5 @@ public class SimpleMessagingGateway extends AbstractMessagingGateway {
}
return message;
}
}

View File

@@ -23,7 +23,9 @@ import org.springframework.core.Ordered;
import org.springframework.integration.Message;
import org.springframework.integration.MessageHandlingException;
import org.springframework.integration.MessagingException;
import org.springframework.integration.context.HistoryProvider;
import org.springframework.integration.context.IntegrationObjectSupport;
import org.springframework.integration.context.MessageHistoryWriter;
import org.springframework.integration.core.MessageHandler;
import org.springframework.util.Assert;
@@ -36,10 +38,12 @@ import org.springframework.util.Assert;
* @author Mark Fisher
* @author Oleg Zhurakousky
*/
public abstract class AbstractMessageHandler extends IntegrationObjectSupport implements MessageHandler, Ordered {
public abstract class AbstractMessageHandler extends IntegrationObjectSupport implements MessageHandler, HistoryProvider, Ordered {
protected final Log logger = LogFactory.getLog(this.getClass());
private volatile boolean shouldIncludeInHistory = false;
private volatile int order = Ordered.LOWEST_PRECEDENCE;
@@ -56,6 +60,10 @@ public abstract class AbstractMessageHandler extends IntegrationObjectSupport im
return "message-handler";
}
public void setShouldIncludeInHistory(boolean shouldIncludeInHistory) {
this.shouldIncludeInHistory = shouldIncludeInHistory;
}
public final void handleMessage(Message<?> message) {
Assert.notNull(message, "Message must not be null");
Assert.notNull(message.getPayload(), "Message payload must not be null");
@@ -63,6 +71,9 @@ public abstract class AbstractMessageHandler extends IntegrationObjectSupport im
this.logger.debug(this + " received message: " + message);
}
try {
if (message != null && this.shouldIncludeInHistory) {
message = MessageHistoryWriter.writeHistory(this, message);
}
this.handleMessageInternal(message);
}
catch (Exception e) {

View File

@@ -24,7 +24,6 @@ import org.springframework.core.Ordered;
import org.springframework.integration.Message;
import org.springframework.integration.MessageHandlingException;
import org.springframework.integration.context.BeanFactoryChannelResolver;
import org.springframework.integration.context.IntegrationObjectSupport;
import org.springframework.integration.core.ChannelResolver;
import org.springframework.integration.core.MessageChannel;
import org.springframework.integration.core.MessageHandler;
@@ -63,7 +62,7 @@ import org.springframework.util.Assert;
* @author Mark Fisher
* @author Iwein Fuld
*/
public class MessageHandlerChain extends IntegrationObjectSupport implements MessageHandler, MessageProducer, Ordered {
public class MessageHandlerChain extends AbstractMessageHandler implements MessageProducer, Ordered {
private volatile List<MessageHandler> handlers;
@@ -111,7 +110,8 @@ public class MessageHandlerChain extends IntegrationObjectSupport implements Mes
return "chain";
}
private void initialize() {
@Override
protected void onInit() throws Exception {
synchronized (this.initializationMonitor) {
if (!this.initialized) {
Assert.notEmpty(this.handlers, "handler list must not be empty");
@@ -125,9 +125,10 @@ public class MessageHandlerChain extends IntegrationObjectSupport implements Mes
}
}
public void handleMessage(Message<?> message) {
@Override
protected void handleMessageInternal(Message<?> message) throws Exception {
if (!this.initialized) {
this.initialize();
this.onInit();
}
this.handlers.get(0).handleMessage(message);
}

View File

@@ -86,7 +86,7 @@ public class MessageHandlerChainTests {
chain.setBeanName("testChain");
chain.setHandlers(handlers);
chain.setOutputChannel(outputChannel);
chain.handleMessage(message);
chain.afterPropertiesSet();
}
@Test
@@ -156,7 +156,6 @@ public class MessageHandlerChainTests {
@Test(expected = IllegalArgumentException.class) // INT-1175
public void chainRejectsDuplicateHandlers() {
Message<String> message = MessageBuilder.withPayload("test").setReplyChannelName("testChannel").build();
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("testChannel", outputChannel);
List<MessageHandler> handlers = new ArrayList<MessageHandler>();
@@ -167,7 +166,7 @@ public class MessageHandlerChainTests {
chain.setBeanName("testChain");
chain.setHandlers(handlers);
chain.setBeanFactory(beanFactory);
chain.handleMessage(message);
chain.afterPropertiesSet();
}

View File

@@ -26,6 +26,7 @@ import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.Mockito;
@@ -46,7 +47,7 @@ import org.springframework.integration.core.MessageHandler;
*/
public class MessageHistoryIntegrationTests {
@Test
@Test @Ignore
public void testHistoryAwareMessageHandler() {
ApplicationContext ac = new ClassPathXmlApplicationContext("messageHistoryWithHistoryWriter.xml", MessageHistoryIntegrationTests.class);
Map<String, ConsumerEndpointFactoryBean> cefBeans = ac.getBeansOfType(ConsumerEndpointFactoryBean.class);

View File

@@ -30,5 +30,5 @@
<int:channel id="endOfThePipeChannel"/>
<bean class="org.springframework.integration.context.MessageHistoryWriter"/>
<bean class="org.springframework.integration.context.MessageHistoryBeanPostProcessor"/>
</beans>

View File

@@ -7,4 +7,5 @@
<int:message-history/>
<int:message-history/>
</beans>

View File

@@ -27,6 +27,7 @@ import javax.jms.Session;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.integration.Message;
import org.springframework.integration.context.MessageHistoryWriter;
import org.springframework.integration.core.MessageBuilder;
import org.springframework.integration.gateway.AbstractMessagingGateway;
import org.springframework.jms.listener.SessionAwareMessageListener;
@@ -222,7 +223,7 @@ public class ChannelPublishingJmsMessageListener extends AbstractMessagingGatewa
Message<?> requestMessage = (object instanceof Message<?>) ?
MessageBuilder.fromMessage((Message<?>) object).copyHeaders(headers).build() :
MessageBuilder.withPayload(object).copyHeaders(headers).build();
requestMessage = this.writeMessageHistory(requestMessage);
requestMessage = MessageHistoryWriter.writeHistory(this, requestMessage);
if (!this.expectReply) {
this.send(requestMessage);
}

View File

@@ -23,6 +23,7 @@ import javax.jms.Destination;
import org.springframework.integration.Message;
import org.springframework.integration.MessagingException;
import org.springframework.integration.context.MessageHistoryWriter;
import org.springframework.integration.core.MessageBuilder;
import org.springframework.integration.core.MessageSource;
import org.springframework.jms.core.JmsTemplate;
@@ -87,7 +88,7 @@ public class JmsDestinationPollingSource extends AbstractJmsTemplateBasedAdapter
MessageBuilder<Object> builder = (convertedObject instanceof Message)
? MessageBuilder.fromMessage((Message<Object>) convertedObject) : MessageBuilder.withPayload(convertedObject);
convertedMessage = builder.copyHeadersIfAbsent(mappedHeaders).build();
convertedMessage = this.writeMessageHistory(convertedMessage);
convertedMessage = MessageHistoryWriter.writeHistory(this, convertedMessage);
}
catch (Exception e) {
throw new MessagingException(e.getMessage(), e);

View File

@@ -20,6 +20,7 @@ import javax.jms.JMSException;
import org.springframework.core.Ordered;
import org.springframework.integration.Message;
import org.springframework.integration.context.MessageHistoryWriter;
import org.springframework.integration.core.MessageHandler;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessagePostProcessor;
@@ -62,7 +63,7 @@ public class JmsSendingMessageHandler extends AbstractJmsTemplateBasedAdapter im
if (message == null) {
throw new IllegalArgumentException("message must not be null");
}
final Message<?> messageToSend = this.writeMessageHistory(message);
final Message<?> messageToSend = MessageHistoryWriter.writeHistory(this, message);
this.getJmsTemplate().convertAndSend(messageToSend, new MessagePostProcessor() {
public javax.jms.Message postProcessMessage(javax.jms.Message jmsMessage)
throws JMSException {

View File

@@ -10,7 +10,7 @@
xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:task="http://www.springframework.org/schema/task">
<int:gateway id="sampleGateway"
service-interface="org.springframework.integration.jms.config.JmsMessageHistoryTests$SampleGateway"
default-request-channel="outbound-channel">
@@ -19,8 +19,7 @@
<int:channel id="outbound-channel"/>
<int-jms:outbound-channel-adapter id="jmsOutbound" channel="outbound-channel" destination-name="request.queue_c"/>
<int-jms:inbound-channel-adapter id="sampleJmsInboundAdapter" channel="jmsInputChannel" destination-name="request.queue_c"/>
<int:channel id="jmsInputChannel">
@@ -41,6 +40,6 @@
<property name="cacheProducers" value="false"/>
</bean>
<bean id="historyWriter" class="org.springframework.integration.context.MessageHistoryWriter"/>
<bean class="org.springframework.integration.context.MessageHistoryBeanPostProcessor"/>
</beans>