diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/AbstractCorrelatingMessageHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/AbstractCorrelatingMessageHandler.java index cf35260f8f..40f99c558f 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/AbstractCorrelatingMessageHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/AbstractCorrelatingMessageHandler.java @@ -22,7 +22,9 @@ import java.util.concurrent.locks.Lock; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.integration.IntegrationMessageHeaderAccessor; import org.springframework.integration.channel.NullChannel; import org.springframework.integration.core.MessageProducer; @@ -40,8 +42,10 @@ import org.springframework.integration.util.UUIDConverter; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessagingException; +import org.springframework.messaging.core.DestinationResolutionException; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; /** * Abstract Message handler that holds a buffer of correlated messages in a @@ -63,6 +67,7 @@ import org.springframework.util.CollectionUtils; * @author Dave Syer * @author Oleg Zhurakousky * @author Gary Russell + * @author Artem Bilan * @since 2.0 */ public abstract class AbstractCorrelatingMessageHandler extends AbstractMessageHandler implements MessageProducer { @@ -81,9 +86,13 @@ public abstract class AbstractCorrelatingMessageHandler extends AbstractMessageH private MessageChannel outputChannel; + private String outputChannelName; + private final MessagingTemplate messagingTemplate = new MessagingTemplate(); - private volatile MessageChannel discardChannel = new NullChannel(); + private volatile MessageChannel discardChannel; + + private volatile String discardChannelName; private boolean sendPartialResultOnExpiry = false; @@ -95,6 +104,8 @@ public abstract class AbstractCorrelatingMessageHandler extends AbstractMessageH private volatile long minimumTimeoutForEmptyGroups; + private volatile boolean releasePartialSequences; + public AbstractCorrelatingMessageHandler(MessageGroupProcessor processor, MessageGroupStore store, CorrelationStrategy correlationStrategy, ReleaseStrategy releaseStrategy) { Assert.notNull(processor); @@ -151,13 +162,60 @@ public abstract class AbstractCorrelatingMessageHandler extends AbstractMessageH this.outputChannel = outputChannel; } + public void setOutputChannelName(String outputChannelName) { + this.outputChannelName = outputChannelName; + } + @Override protected void onInit() throws Exception { super.onInit(); BeanFactory beanFactory = this.getBeanFactory(); if (beanFactory != null) { this.messagingTemplate.setBeanFactory(beanFactory); + if (StringUtils.hasText(this.discardChannelName)) { + Assert.isNull(this.discardChannel, "'outputChannelName' and 'discardChannel' are mutually exclusive."); + try { + this.discardChannel = beanFactory.getBean(this.discardChannelName, MessageChannel.class); + } + catch (BeansException e) { + throw new DestinationResolutionException("Failed to look up MessageChannel with name '" + + this.discardChannelName + "' in the BeanFactory."); + } + } + + if (StringUtils.hasText(this.outputChannelName)) { + Assert.isNull(this.outputChannel, "'outputChannelName' and 'outputChannel' are mutually exclusive."); + try { + this.outputChannel = this.getBeanFactory().getBean(this.outputChannelName, MessageChannel.class); + } + catch (BeansException e) { + throw new DestinationResolutionException("Failed to look up MessageChannel with name '" + + this.outputChannelName + "' in the BeanFactory."); + } + } + + if (this.outputProcessor instanceof BeanFactoryAware) { + ((BeanFactoryAware) this.outputProcessor).setBeanFactory(beanFactory); + } + if (this.correlationStrategy instanceof BeanFactoryAware) { + ((BeanFactoryAware) this.correlationStrategy).setBeanFactory(beanFactory); + } + if (this.releaseStrategy instanceof BeanFactoryAware) { + ((BeanFactoryAware) this.releaseStrategy).setBeanFactory(beanFactory); + } } + + if (this.discardChannel == null) { + this.discardChannel = new NullChannel(); + } + + if (this.releasePartialSequences) { + Assert.isInstanceOf(SequenceSizeReleaseStrategy.class, this.releaseStrategy, + "Release strategy of type [" + this.releaseStrategy.getClass().getSimpleName() + + "] cannot release partial sequences. Use the default SequenceSizeReleaseStrategy instead."); + ((SequenceSizeReleaseStrategy)this.releaseStrategy).setReleasePartialSequences(releasePartialSequences); + } + /* * Disallow any further changes to the lock registry * (checked in the setter). @@ -166,9 +224,14 @@ public abstract class AbstractCorrelatingMessageHandler extends AbstractMessageH } public void setDiscardChannel(MessageChannel discardChannel) { + Assert.notNull(discardChannel, "'discardChannel' cannot be null"); this.discardChannel = discardChannel; } + public void setDiscardChannelName(String discardChannelName) { + this.discardChannelName = discardChannelName; + } + public void setSendTimeout(long sendTimeout) { this.messagingTemplate.setSendTimeout(sendTimeout); } @@ -192,11 +255,8 @@ public abstract class AbstractCorrelatingMessageHandler extends AbstractMessageH this.minimumTimeoutForEmptyGroups = minimumTimeoutForEmptyGroups; } - public void setReleasePartialSequences(boolean releasePartialSequences){ - Assert.isInstanceOf(SequenceSizeReleaseStrategy.class, this.releaseStrategy, - "Release strategy of type [" + this.releaseStrategy.getClass().getSimpleName() - + "] cannot release partial sequences. Use the default SequenceSizeReleaseStrategy instead."); - ((SequenceSizeReleaseStrategy)this.releaseStrategy).setReleasePartialSequences(releasePartialSequences); + public void setReleasePartialSequences(boolean releasePartialSequences) { + this.releasePartialSequences = releasePartialSequences; } @Override diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingCorrelationStrategy.java b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingCorrelationStrategy.java index afd5c448f8..fc5f5889d2 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingCorrelationStrategy.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/ExpressionEvaluatingCorrelationStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -19,13 +19,12 @@ package org.springframework.integration.aggregator; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.InitializingBean; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.SpelParserConfiguration; import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.messaging.Message; import org.springframework.integration.handler.ExpressionEvaluatingMessageProcessor; +import org.springframework.messaging.Message; import org.springframework.util.Assert; /** @@ -33,13 +32,12 @@ import org.springframework.util.Assert; * * @author Dave Syer * @author Oleg Zhurakousky + * @author Artem Bilan */ -public class ExpressionEvaluatingCorrelationStrategy implements CorrelationStrategy, BeanFactoryAware, InitializingBean{ +public class ExpressionEvaluatingCorrelationStrategy implements CorrelationStrategy, BeanFactoryAware { private static final ExpressionParser expressionParser = new SpelExpressionParser(new SpelParserConfiguration(true, true)); - private volatile BeanFactory beanFactory; - private final ExpressionEvaluatingMessageProcessor processor; @@ -58,12 +56,8 @@ public class ExpressionEvaluatingCorrelationStrategy implements CorrelationStrat } public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = beanFactory; - } - - public void afterPropertiesSet() throws Exception { - if (this.beanFactory != null){ - this.processor.setBeanFactory(this.beanFactory); + if (beanFactory != null){ + this.processor.setBeanFactory(beanFactory); } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingCorrelationStrategy.java b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingCorrelationStrategy.java index 16b9d127ee..b5f4c1ef72 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingCorrelationStrategy.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingCorrelationStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2014 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. @@ -18,8 +18,12 @@ package org.springframework.integration.aggregator; import java.lang.reflect.Method; -import org.springframework.messaging.Message; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.integration.handler.MessageProcessor; import org.springframework.integration.handler.MethodInvokingMessageProcessor; +import org.springframework.messaging.Message; import org.springframework.util.Assert; /** @@ -27,10 +31,11 @@ import org.springframework.util.Assert; * * @author Marius Bogoevici * @author Dave Syer + * @author Artem Bilan */ -public class MethodInvokingCorrelationStrategy implements CorrelationStrategy { +public class MethodInvokingCorrelationStrategy implements CorrelationStrategy, BeanFactoryAware { - private final MethodInvokingMessageProcessor processor; + private final MessageProcessor processor; public MethodInvokingCorrelationStrategy(Object object, String methodName) { this.processor = new MethodInvokingMessageProcessor(object, methodName, true); @@ -43,8 +48,15 @@ public class MethodInvokingCorrelationStrategy implements CorrelationStrategy { this.processor = new MethodInvokingMessageProcessor(object, method); } + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + if (beanFactory != null && this.processor instanceof BeanFactoryAware) { + ((BeanFactoryAware) this.processor).setBeanFactory(beanFactory); + } + } + + @Override public Object getCorrelationKey(Message message) { return processor.processMessage(message); } - } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingReleaseStrategy.java b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingReleaseStrategy.java index 88f81ef730..daaa9a6d28 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingReleaseStrategy.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/MethodInvokingReleaseStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2014 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. @@ -19,16 +19,17 @@ package org.springframework.integration.aggregator; import java.lang.reflect.Method; import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.core.convert.ConversionService; import org.springframework.integration.store.MessageGroup; /** - * A {@link ReleaseStrategy} that invokes a method on a plain old Java object. - * + * A {@link ReleaseStrategy} that invokes a method on a plain old Java object. + * * @author Marius Bogoevici * @author Dave Syer */ -public class MethodInvokingReleaseStrategy implements ReleaseStrategy { +public class MethodInvokingReleaseStrategy implements ReleaseStrategy, BeanFactoryAware { private final MethodInvokingMessageListProcessor adapter; @@ -46,10 +47,12 @@ public class MethodInvokingReleaseStrategy implements ReleaseStrategy { this.adapter.setConversionService(conversionService); } + @Override public void setBeanFactory(BeanFactory beanFactory) { this.adapter.setBeanFactory(beanFactory); } + @Override public boolean canRelease(MessageGroup messages) { return this.adapter.process(messages.getMessages(), null); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ResequencerParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ResequencerParser.java index a22c3759c8..3602c63252 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ResequencerParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ResequencerParser.java @@ -16,11 +16,9 @@ package org.springframework.integration.config.xml; import org.w3c.dom.Element; import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.integration.aggregator.ResequencingMessageGroupProcessor; import org.springframework.integration.aggregator.ResequencingMessageHandler; -import org.springframework.integration.store.SimpleMessageStore; /** * Parser for the <resequencer> element. @@ -32,9 +30,6 @@ import org.springframework.integration.store.SimpleMessageStore; */ public class ResequencerParser extends AbstractCorrelatingMessageHandlerParser { - - private static final String COMPARATOR_REF_ATTRIBUTE = "comparator"; - private static final String RELEASE_PARTIAL_SEQUENCES_ATTRIBUTE = "release-partial-sequences"; @Override @@ -43,17 +38,7 @@ public class ResequencerParser extends AbstractCorrelatingMessageHandlerParser { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ResequencingMessageHandler.class); BeanDefinitionBuilder processorBuilder = BeanDefinitionBuilder.genericBeanDefinition(ResequencingMessageGroupProcessor.class); - // Comparator - IntegrationNamespaceUtils.setReferenceIfAttributeDefined(processorBuilder, element, COMPARATOR_REF_ATTRIBUTE); - - String processorRef = BeanDefinitionReaderUtils.registerWithGeneratedName(processorBuilder.getBeanDefinition(), - parserContext.getRegistry()); - - // Message group processor - builder.addConstructorArgReference(processorRef); - - // Message store - builder.addConstructorArgValue(BeanDefinitionBuilder.genericBeanDefinition(SimpleMessageStore.class).getBeanDefinition()); + builder.addConstructorArgValue(processorBuilder.getBeanDefinition()); this.doParse(builder, element, processorBuilder.getBeanDefinition(), parserContext); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/filter/MessageFilter.java b/spring-integration-core/src/main/java/org/springframework/integration/filter/MessageFilter.java index 35d38dcc39..70be1124c4 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/filter/MessageFilter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/filter/MessageFilter.java @@ -16,13 +16,16 @@ package org.springframework.integration.filter; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.integration.MessageRejectedException; import org.springframework.integration.core.MessageSelector; import org.springframework.integration.handler.AbstractReplyProducingPostProcessingMessageHandler; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.core.DestinationResolutionException; import org.springframework.util.Assert; +import org.springframework.util.StringUtils; /** * Message Handler that delegates to a {@link MessageSelector}. If and only if @@ -36,6 +39,7 @@ import org.springframework.util.Assert; * @author Mark Fisher * @author Oleg Zhurakousky * @author Gary Russell + * @author Artem Bilan */ public class MessageFilter extends AbstractReplyProducingPostProcessingMessageHandler { @@ -45,6 +49,7 @@ public class MessageFilter extends AbstractReplyProducingPostProcessingMessageHa private volatile MessageChannel discardChannel; + private volatile String discardChannelName; /** * Create a MessageFilter that will delegate to the given @@ -90,6 +95,10 @@ public class MessageFilter extends AbstractReplyProducingPostProcessingMessageHa this.discardChannel = discardChannel; } + public void setDiscardChannelName(String discardChannelName) { + this.discardChannelName = discardChannelName; + } + /** * Set to 'true' if you wish the discard processing to occur within any * request handler advice applied to this filter. Also applies to @@ -108,6 +117,16 @@ public class MessageFilter extends AbstractReplyProducingPostProcessingMessageHa @Override protected void doInit() { + if (StringUtils.hasText(this.discardChannelName)) { + Assert.isNull(this.discardChannel, "'outputChannelName' and 'discardChannel' are mutually exclusive."); + try { + this.discardChannel = this.getBeanFactory().getBean(this.discardChannelName, MessageChannel.class); + } + catch (BeansException e) { + throw new DestinationResolutionException("Failed to look up MessageChannel with name '" + + this.discardChannelName + "' in the BeanFactory."); + } + } if (this.selector instanceof AbstractMessageProcessingSelector) { ((AbstractMessageProcessingSelector) this.selector).setConversionService(this.getConversionService()); } diff --git a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-4.0.xsd b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-4.0.xsd index d0ddf26285..9c177ebff1 100644 --- a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-4.0.xsd +++ b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-4.0.xsd @@ -3520,20 +3520,6 @@ - - - - Comparator for messages used to sort the sequence when released. Defaults to comparing - the - sequence number header. - - - - - - - - diff --git a/spring-integration-core/src/test/java/org/springframework/integration/aggregator/AggregatorTests.java b/spring-integration-core/src/test/java/org/springframework/integration/aggregator/AggregatorTests.java index d29931e97e..ac00cd2644 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/aggregator/AggregatorTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/aggregator/AggregatorTests.java @@ -47,6 +47,7 @@ public class AggregatorTests { @Before public void configureAggregator() { this.aggregator = new AggregatingMessageHandler(new MultiplyingProcessor(), store); + this.aggregator.afterPropertiesSet(); } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/aggregator/CorrelatingMessageHandlerIntegrationTests.java b/spring-integration-core/src/test/java/org/springframework/integration/aggregator/CorrelatingMessageHandlerIntegrationTests.java index 474f9f3b03..91b968c4ba 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/aggregator/CorrelatingMessageHandlerIntegrationTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/aggregator/CorrelatingMessageHandlerIntegrationTests.java @@ -16,20 +16,21 @@ package org.springframework.integration.aggregator; -import org.junit.Before; -import org.junit.Test; -import org.springframework.messaging.Message; -import org.springframework.messaging.MessageChannel; -import org.springframework.integration.store.MessageGroupStore; -import org.springframework.integration.store.SimpleMessageStore; -import org.springframework.integration.support.MessageBuilder; - import static org.mockito.Matchers.isA; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import org.junit.Before; +import org.junit.Test; + +import org.springframework.integration.store.MessageGroupStore; +import org.springframework.integration.store.SimpleMessageStore; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageChannel; + public class CorrelatingMessageHandlerIntegrationTests { private MessageGroupStore store = new SimpleMessageStore(100); @@ -45,6 +46,7 @@ public class CorrelatingMessageHandlerIntegrationTests { when(outputChannel.send(isA(Message.class))).thenReturn(true); defaultHandler.setOutputChannel(outputChannel); defaultHandler.setSendTimeout(-1); + defaultHandler.afterPropertiesSet(); } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/aggregator/ExpressionEvaluatingCorrelationStrategyTests.java b/spring-integration-core/src/test/java/org/springframework/integration/aggregator/ExpressionEvaluatingCorrelationStrategyTests.java index 5ae6a395b3..cbe8a71c7d 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/aggregator/ExpressionEvaluatingCorrelationStrategyTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/aggregator/ExpressionEvaluatingCorrelationStrategyTests.java @@ -61,7 +61,6 @@ public class ExpressionEvaluatingCorrelationStrategyTests { Expression expression = parser.parseExpression("payload.substring(0,1)"); strategy = new ExpressionEvaluatingCorrelationStrategy(expression); strategy.setBeanFactory(mock(BeanFactory.class)); - strategy.afterPropertiesSet(); Object correlationKey = strategy.getCorrelationKey(new GenericMessage("bla")); assertThat(correlationKey, is(instanceOf(String.class))); assertThat((String) correlationKey, is("b")); diff --git a/spring-integration-core/src/test/java/org/springframework/integration/aggregator/ResequencerTests.java b/spring-integration-core/src/test/java/org/springframework/integration/aggregator/ResequencerTests.java index e8205de4da..4dde51edd4 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/aggregator/ResequencerTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/aggregator/ResequencerTests.java @@ -54,6 +54,7 @@ public class ResequencerTests { @Before public void configureResequencer() { this.resequencer = new ResequencingMessageHandler(processor, store, null, null); + this.resequencer.afterPropertiesSet(); } @Test @@ -81,6 +82,7 @@ public class ResequencerTests { SequenceSizeReleaseStrategy releaseStrategy = new SequenceSizeReleaseStrategy(); releaseStrategy.setReleasePartialSequences(true); this.resequencer = new ResequencingMessageHandler(processor, store, null, releaseStrategy); + this.resequencer.afterPropertiesSet(); QueueChannel replyChannel = new QueueChannel(); Message message1 = createMessage("123", "ABC", 3, 1, replyChannel); @@ -104,6 +106,8 @@ public class ResequencerTests { return "A"; } }); + this.resequencer.afterPropertiesSet(); + //Message message0 = MessageBuilder.withPayload("0").setSequenceNumber(0).build(); Message message1 = MessageBuilder.withPayload("1").setSequenceNumber(1).setReplyChannel(replyChannel).build(); Message message2 = MessageBuilder.withPayload("2").setSequenceNumber(2).setReplyChannel(replyChannel).build(); diff --git a/spring-integration-core/src/test/java/org/springframework/integration/aggregator/integration/AggregatorIntegrationTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/aggregator/integration/AggregatorIntegrationTests-context.xml index 2a47c4f506..599fc36fa2 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/aggregator/integration/AggregatorIntegrationTests-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/aggregator/integration/AggregatorIntegrationTests-context.xml @@ -11,7 +11,7 @@ - + @@ -20,19 +20,19 @@ - + - - - - - - \ No newline at end of file + + + + + + diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XPathHeaderEnricherParser.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XPathHeaderEnricherParser.java index f54838aa46..6c5a3545ca 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XPathHeaderEnricherParser.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XPathHeaderEnricherParser.java @@ -26,6 +26,7 @@ import org.springframework.beans.factory.xml.ParserContext; import org.springframework.integration.config.xml.AbstractTransformerParser; import org.springframework.integration.config.xml.IntegrationNamespaceUtils; import org.springframework.integration.xml.transformer.XPathHeaderEnricher; +import org.springframework.integration.xml.transformer.support.XPathExpressionEvaluatingHeaderValueMessageProcessor; import org.springframework.util.StringUtils; /** @@ -61,7 +62,7 @@ public class XPathHeaderEnricherParser extends AbstractTransformerParser { String elementName = node.getLocalName(); if ("header".equals(elementName)) { BeanDefinitionBuilder builder = - BeanDefinitionBuilder.genericBeanDefinition(XPathHeaderEnricher.XPathExpressionEvaluatingHeaderValueMessageProcessor.class); + BeanDefinitionBuilder.genericBeanDefinition(XPathExpressionEvaluatingHeaderValueMessageProcessor.class); String expressionString = headerElement.getAttribute("xpath-expression"); String expressionRef = headerElement.getAttribute("xpath-expression-ref"); boolean isExpressionString = StringUtils.hasText(expressionString); diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/XPathHeaderEnricher.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/XPathHeaderEnricher.java index 53aa553741..9deb67d2aa 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/XPathHeaderEnricher.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/XPathHeaderEnricher.java @@ -18,24 +18,8 @@ package org.springframework.integration.xml.transformer; import java.util.Map; -import org.w3c.dom.Node; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.core.convert.ConversionService; -import org.springframework.core.convert.TypeDescriptor; -import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.integration.transformer.HeaderEnricher; -import org.springframework.integration.transformer.support.HeaderValueMessageProcessor; -import org.springframework.integration.util.BeanFactoryTypeConverter; -import org.springframework.integration.xml.DefaultXmlPayloadConverter; -import org.springframework.integration.xml.XmlPayloadConverter; -import org.springframework.integration.xml.xpath.XPathEvaluationType; -import org.springframework.messaging.Message; -import org.springframework.util.Assert; -import org.springframework.xml.xpath.XPathExpression; -import org.springframework.xml.xpath.XPathExpressionFactory; +import org.springframework.integration.xml.transformer.support.XPathExpressionEvaluatingHeaderValueMessageProcessor; /** * Transformer implementation that evaluates XPath expressions against the @@ -44,7 +28,6 @@ import org.springframework.xml.xpath.XPathExpressionFactory; * * @author Jonas Partner * @author Mark Fisher - * @author Artem Bilan * @since 2.0 */ public class XPathHeaderEnricher extends HeaderEnricher { @@ -60,72 +43,4 @@ public class XPathHeaderEnricher extends HeaderEnricher { } - public static class XPathExpressionEvaluatingHeaderValueMessageProcessor implements HeaderValueMessageProcessor, - BeanFactoryAware { - - private static final XmlPayloadConverter converter = new DefaultXmlPayloadConverter(); - - private final BeanFactoryTypeConverter typeConverter = new BeanFactoryTypeConverter(); - - private final XPathExpression expression; - - private volatile XPathEvaluationType evaluationType = XPathEvaluationType.STRING_RESULT; - - private volatile TypeDescriptor headerTypeDescriptor; - - private volatile Boolean overwrite = null; - - public XPathExpressionEvaluatingHeaderValueMessageProcessor(String expression) { - Assert.hasText(expression, "expression must have text"); - this.expression = XPathExpressionFactory.createXPathExpression(expression); - } - - public XPathExpressionEvaluatingHeaderValueMessageProcessor(XPathExpression expression) { - Assert.notNull(expression, "expression must not be null"); - this.expression = expression; - } - - public void setEvaluationType(XPathEvaluationType evaluationType) { - this.evaluationType = evaluationType; - } - - public void setHeaderType(Class headerType) { - if (headerType != null) { - this.headerTypeDescriptor = TypeDescriptor.valueOf(headerType); - } - } - - public void setOverwrite(Boolean overwrite) { - this.overwrite = overwrite; - } - - @Override - public Boolean isOverwrite() { - return this.overwrite; - } - - @Override - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - ConversionService conversionService = IntegrationContextUtils.getConversionService(beanFactory); - if (conversionService != null) { - this.typeConverter.setConversionService(conversionService); - } - } - - @Override - public Object processMessage(Message message) { - Node node = converter.convertToNode(message.getPayload()); - Object result = this.evaluationType.evaluateXPath(this.expression, node); - if (result instanceof String && ((String) result).length() == 0) { - result = null; - } - if (result != null && this.headerTypeDescriptor != null) { - return this.typeConverter.convertValue(result, TypeDescriptor.forObject(result), this.headerTypeDescriptor); - } - else { - return result; - } - } - } - } diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/support/XPathExpressionEvaluatingHeaderValueMessageProcessor.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/support/XPathExpressionEvaluatingHeaderValueMessageProcessor.java new file mode 100644 index 0000000000..4e9e6a4202 --- /dev/null +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/support/XPathExpressionEvaluatingHeaderValueMessageProcessor.java @@ -0,0 +1,109 @@ +/* + * Copyright 2014 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.xml.transformer.support; + +import org.w3c.dom.Node; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.integration.context.IntegrationContextUtils; +import org.springframework.integration.transformer.support.HeaderValueMessageProcessor; +import org.springframework.integration.util.BeanFactoryTypeConverter; +import org.springframework.integration.xml.DefaultXmlPayloadConverter; +import org.springframework.integration.xml.XmlPayloadConverter; +import org.springframework.integration.xml.xpath.XPathEvaluationType; +import org.springframework.messaging.Message; +import org.springframework.util.Assert; +import org.springframework.xml.xpath.XPathExpression; +import org.springframework.xml.xpath.XPathExpressionFactory; + +/** + * @author Jonas Partner + * @author Mark Fisher + * @author Artem Bilan + * @since 2.0 +*/ +public class XPathExpressionEvaluatingHeaderValueMessageProcessor implements HeaderValueMessageProcessor, + BeanFactoryAware { + + private static final XmlPayloadConverter converter = new DefaultXmlPayloadConverter(); + + private final BeanFactoryTypeConverter typeConverter = new BeanFactoryTypeConverter(); + + private final XPathExpression expression; + + private volatile XPathEvaluationType evaluationType = XPathEvaluationType.STRING_RESULT; + + private volatile TypeDescriptor headerTypeDescriptor; + + private volatile Boolean overwrite = null; + + public XPathExpressionEvaluatingHeaderValueMessageProcessor(String expression) { + Assert.hasText(expression, "expression must have text"); + this.expression = XPathExpressionFactory.createXPathExpression(expression); + } + + public XPathExpressionEvaluatingHeaderValueMessageProcessor(XPathExpression expression) { + Assert.notNull(expression, "expression must not be null"); + this.expression = expression; + } + + public void setEvaluationType(XPathEvaluationType evaluationType) { + this.evaluationType = evaluationType; + } + + public void setHeaderType(Class headerType) { + if (headerType != null) { + this.headerTypeDescriptor = TypeDescriptor.valueOf(headerType); + } + } + + public void setOverwrite(Boolean overwrite) { + this.overwrite = overwrite; + } + + @Override + public Boolean isOverwrite() { + return this.overwrite; + } + + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + ConversionService conversionService = IntegrationContextUtils.getConversionService(beanFactory); + if (conversionService != null) { + this.typeConverter.setConversionService(conversionService); + } + } + + @Override + public Object processMessage(Message message) { + Node node = converter.convertToNode(message.getPayload()); + Object result = this.evaluationType.evaluateXPath(this.expression, node); + if (result instanceof String && ((String) result).length() == 0) { + result = null; + } + if (result != null && this.headerTypeDescriptor != null) { + return this.typeConverter.convertValue(result, TypeDescriptor.forObject(result), this.headerTypeDescriptor); + } + else { + return result; + } + } +} diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/support/package-info.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/support/package-info.java new file mode 100644 index 0000000000..4e761fc794 --- /dev/null +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/transformer/support/package-info.java @@ -0,0 +1,7 @@ +/** + * Contains support classes for Transformers. + * + * @since 3.0 + * + */ +package org.springframework.integration.xml.transformer.support; diff --git a/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XPathHeaderEnricherTests.java b/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XPathHeaderEnricherTests.java index b8d336a0ad..4158f3efc9 100644 --- a/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XPathHeaderEnricherTests.java +++ b/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XPathHeaderEnricherTests.java @@ -27,7 +27,7 @@ import java.util.TimeZone; import org.junit.Test; import org.springframework.integration.support.MessageBuilder; -import org.springframework.integration.xml.transformer.XPathHeaderEnricher.XPathExpressionEvaluatingHeaderValueMessageProcessor; +import org.springframework.integration.xml.transformer.support.XPathExpressionEvaluatingHeaderValueMessageProcessor; import org.springframework.integration.xml.xpath.XPathEvaluationType; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; diff --git a/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XsltPayloadTransformerTests.java b/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XsltPayloadTransformerTests.java index 71f9e4a791..0b7051863c 100644 --- a/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XsltPayloadTransformerTests.java +++ b/spring-integration-xml/src/test/java/org/springframework/integration/xml/transformer/XsltPayloadTransformerTests.java @@ -27,8 +27,10 @@ import javax.xml.transform.dom.DOMResult; import org.junit.Before; import org.junit.Test; +import org.mockito.Mockito; import org.w3c.dom.Document; +import org.springframework.beans.factory.BeanFactory; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; @@ -58,6 +60,7 @@ public class XsltPayloadTransformerTests { @Before public void setUp() throws Exception { transformer = new XsltPayloadTransformer(getXslResource()); + transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); transformer.afterPropertiesSet(); } @@ -111,6 +114,7 @@ public class XsltPayloadTransformerTests { Integer returnValue = new Integer(13); transformer = new XsltPayloadTransformer(getXslResource(), new StubResultTransformer(returnValue)); + transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); transformer.afterPropertiesSet(); Object transformed = transformer .doTransform(buildMessage(new StringSource(docAsString))); @@ -123,6 +127,7 @@ public class XsltPayloadTransformerTests { Integer returnValue = new Integer(13); transformer = new XsltPayloadTransformer(getXslResource(), new StubResultTransformer(returnValue), "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl"); + transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); transformer.afterPropertiesSet(); Object transformed = transformer .doTransform(buildMessage(new StringSource(docAsString))); @@ -133,6 +138,7 @@ public class XsltPayloadTransformerTests { @Test(expected = TransformerFactoryConfigurationError.class) public void testXsltPayloadWithBadTransformerFactoryClassname() throws Exception { transformer = new XsltPayloadTransformer(getXslResource(), "foo.bar.Baz"); + transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); transformer.afterPropertiesSet(); transformer.doTransform(buildMessage(new StringSource(docAsString))); } @@ -152,6 +158,7 @@ public class XsltPayloadTransformerTests { Resource resource = new ClassPathResource("transform-with-import.xsl", this.getClass()); transformer = new XsltPayloadTransformer(resource); + transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); transformer.afterPropertiesSet(); assertEquals(transformer.doTransform(buildMessage(docAsString)), outputAsString); @@ -165,6 +172,7 @@ public class XsltPayloadTransformerTests { transformer = new XsltPayloadTransformer(resource); transformer.setResultFactory(new StringResultFactory()); transformer.setAlwaysUseResultFactory(true); + transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); transformer.afterPropertiesSet(); Object returned = transformer.doTransform(buildMessage(XmlTestUtil.getDocumentForString(docAsString))); assertEquals("Wrong type of return ", StringResult.class, returned.getClass()); @@ -178,6 +186,7 @@ public class XsltPayloadTransformerTests { transformer = new XsltPayloadTransformer(resource); transformer.setResultFactory(new StringResultFactory()); transformer.setAlwaysUseResultFactory(true); + transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); transformer.afterPropertiesSet(); Object returned = transformer.doTransform(buildMessage(XmlTestUtil.getDocumentForString(docAsString))); assertEquals("Wrong type of return ", StringResult.class, returned.getClass()); @@ -188,6 +197,7 @@ public class XsltPayloadTransformerTests { transformer = new XsltPayloadTransformer(getXslResourceThatOutputsText()); transformer.setResultFactory(new StringResultFactory()); transformer.setAlwaysUseResultFactory(true); + transformer.setBeanFactory(Mockito.mock(BeanFactory.class)); transformer.afterPropertiesSet(); Object returned = transformer.doTransform(buildMessage(XmlTestUtil.getDocumentForString(docAsString))); assertEquals("Wrong type of return ", StringResult.class, returned.getClass()); @@ -199,12 +209,21 @@ public class XsltPayloadTransformerTests { } private Resource getXslResource() throws Exception { - String xsl = "test"; + String xsl = "" + + "" + + " " + + " test" + + " " + + ""; return new ByteArrayResource(xsl.getBytes("UTF-8")); } private Resource getXslResourceThatOutputsText() throws Exception { - String xsl = "hello world"; + String xsl = "" + + "" + + " " + + " hello world" + + ""; return new ByteArrayResource(xsl.getBytes("UTF-8")); }