diff --git a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests.java b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests.java index 9cad51a2c6..d1fd4663c6 100644 --- a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests.java +++ b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -41,8 +42,11 @@ import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.rabbit.support.CorrelationData; import org.springframework.amqp.rabbit.support.PublisherCallbackChannel; import org.springframework.amqp.rabbit.support.PublisherCallbackChannelImpl; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.integration.Message; import org.springframework.integration.MessageChannel; import org.springframework.integration.amqp.AmqpHeaders; @@ -222,6 +226,19 @@ public class AmqpOutboundChannelAdapterParserTests { assertEquals("hello", returned.getPayload()); } + @Test + public void testInt2718FailForOutboundAdapterChannelAttribute() { + try { + new ClassPathXmlApplicationContext("AmqpOutboundChannelAdapterWithinChainParserTests-fail-context.xml", this.getClass()); + fail("Expected BeanDefinitionParsingException"); + } + catch (BeansException e) { + assertTrue(e instanceof BeanDefinitionParsingException); + assertTrue(e.getMessage().contains("The 'channel' attribute isn't allowed for 'amqp:outbound-channel-adapter' " + + "when it is used as a nested element")); + } + } + public static class FooAdvice extends AbstractRequestHandlerAdvice { @Override diff --git a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterWithinChainParserTests-fail-context.xml b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterWithinChainParserTests-fail-context.xml new file mode 100644 index 0000000000..f6c0bc9200 --- /dev/null +++ b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterWithinChainParserTests-fail-context.xml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractConsumerEndpointParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractConsumerEndpointParser.java index 4629ff3874..805a90bb24 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractConsumerEndpointParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractConsumerEndpointParser.java @@ -79,22 +79,31 @@ public abstract class AbstractConsumerEndpointParser extends AbstractBeanDefinit BeanDefinitionBuilder handlerBuilder = this.parseHandler(element, parserContext); IntegrationNamespaceUtils.setReferenceIfAttributeDefined(handlerBuilder, element, "output-channel"); IntegrationNamespaceUtils.setValueIfAttributeDefined(handlerBuilder, element, "order"); - AbstractBeanDefinition handlerBeanDefinition = handlerBuilder.getBeanDefinition(); - String inputChannelAttributeName = this.getInputChannelAttributeName(); - if (!element.hasAttribute(inputChannelAttributeName)) { - if (!parserContext.isNested()) { - String elementDescription = IntegrationNamespaceUtils.createElementDescription(element); - parserContext.getReaderContext().error("The '" + inputChannelAttributeName - + "' attribute is required for the top-level endpoint element " - + elementDescription + ".", element); - } - return handlerBeanDefinition; - } Element adviceChainElement = DomUtils.getChildElementByTagName(element, IntegrationNamespaceUtils.REQUEST_HANDLER_ADVICE_CHAIN); IntegrationNamespaceUtils.configureAndSetAdviceChainIfPresent(adviceChainElement, null, - handlerBuilder, parserContext); + handlerBuilder.getRawBeanDefinition(), parserContext); + + AbstractBeanDefinition handlerBeanDefinition = handlerBuilder.getBeanDefinition(); + String inputChannelAttributeName = this.getInputChannelAttributeName(); + boolean hasInputChannelAttribute = element.hasAttribute(inputChannelAttributeName); + if (parserContext.isNested()) { + if (hasInputChannelAttribute) { + String elementDescription = IntegrationNamespaceUtils.createElementDescription(element); + parserContext.getReaderContext().error("The '" + inputChannelAttributeName + + "' attribute isn't allowed for a nested (e.g. inside a ) endpoint element: " + + elementDescription + ".", element); + } + return handlerBeanDefinition; + } else { + if (!hasInputChannelAttribute) { + String elementDescription = IntegrationNamespaceUtils.createElementDescription(element); + parserContext.getReaderContext().error("The '" + inputChannelAttributeName + + "' attribute is required for the top-level endpoint element: " + + elementDescription + ".", element); + } + } BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ConsumerEndpointFactoryBean.class); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractOutboundChannelAdapterParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractOutboundChannelAdapterParser.java index 6d77f21953..0778cd4cad 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractOutboundChannelAdapterParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractOutboundChannelAdapterParser.java @@ -46,7 +46,17 @@ public abstract class AbstractOutboundChannelAdapterParser extends AbstractChann @Override protected AbstractBeanDefinition doParse(Element element, ParserContext parserContext, String channelName) { if (parserContext.isNested()) { - return this.parseConsumer(element, parserContext); + if (channelName != null) { + String elementDescription = IntegrationNamespaceUtils.createElementDescription(element); + parserContext.getReaderContext().error( + "The 'channel' attribute isn't allowed for " + + elementDescription + + " when it is used as a nested element," + + " e.g. inside a ", element); + } + AbstractBeanDefinition consumerBeanDefinition = this.parseConsumer(element, parserContext); + this.configureRequestHandlerAdviceChain(element, parserContext, consumerBeanDefinition, null); + return consumerBeanDefinition; } BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ConsumerEndpointFactoryBean.class); Element pollerElement = DomUtils.getChildElementByTagName(element, "poller"); @@ -62,13 +72,19 @@ public abstract class AbstractOutboundChannelAdapterParser extends AbstractChann builder.addPropertyValue("inputChannelName", channelName); IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "auto-startup"); + this.configureRequestHandlerAdviceChain(element, parserContext, handlerBeanComponentDefinition.getBeanDefinition(), builder); + + return builder.getBeanDefinition(); + } + + private void configureRequestHandlerAdviceChain(Element element, ParserContext parserContext, + BeanDefinition handlerBeanDefinition, BeanDefinitionBuilder consumerBuilder) { Element adviceChainElement = DomUtils.getChildElementByTagName(element, IntegrationNamespaceUtils.REQUEST_HANDLER_ADVICE_CHAIN); @SuppressWarnings("rawtypes") - ManagedList adviceChain = IntegrationNamespaceUtils.configureAdviceChain(adviceChainElement, null, - builder, parserContext); + ManagedList adviceChain = + IntegrationNamespaceUtils.configureAdviceChain(adviceChainElement, null, handlerBeanDefinition, parserContext); if (adviceChain != null) { - BeanDefinition handlerBeanDefinition = handlerBeanComponentDefinition.getBeanDefinition(); /* * For ARPMH, the advice chain is injected so just the handleRequestMessage method is advised. * Sometime ARPMHs do double duty as a gateway and a channel adapter. The parser subclass @@ -90,12 +106,17 @@ public abstract class AbstractOutboundChannelAdapterParser extends AbstractChann if (isReplyProducer) { handlerBeanDefinition.getPropertyValues().add("adviceChain", adviceChain); } + else if (consumerBuilder != null) { + consumerBuilder.addPropertyValue("adviceChain", adviceChain); + } else { - builder.addPropertyValue("adviceChain", adviceChain); + String elementDescription = IntegrationNamespaceUtils.createElementDescription(element); + parserContext.getReaderContext().error("'request-handler-advice-chain' isn't allowed for " + + elementDescription + + " within a , because its Handler " + + "isn't an AbstractReplyProducingMessageHandler", element); } } - - return builder.getBeanDefinition(); } /** diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/DelayerParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/DelayerParser.java index 4e124399f8..9c2ed01553 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/DelayerParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/DelayerParser.java @@ -72,8 +72,8 @@ public class DelayerParser extends AbstractConsumerEndpointParser { Element txElement = DomUtils.getChildElementByTagName(element, "transactional"); Element adviceChainElement = DomUtils.getChildElementByTagName(element, "advice-chain"); - IntegrationNamespaceUtils.configureAndSetAdviceChainIfPresent(adviceChainElement, txElement, builder, - parserContext, "delayedAdviceChain"); + IntegrationNamespaceUtils.configureAndSetAdviceChainIfPresent(adviceChainElement, txElement, + builder.getRawBeanDefinition(), parserContext, "delayedAdviceChain"); return builder; } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java index 6ab28d808e..361cad56bd 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/IntegrationNamespaceUtils.java @@ -329,22 +329,22 @@ public abstract class IntegrationNamespaceUtils { } public static void configureAndSetAdviceChainIfPresent(Element adviceChainElement, Element txElement, - BeanDefinitionBuilder parentBuilder, ParserContext parserContext) { - configureAndSetAdviceChainIfPresent(adviceChainElement, txElement, parentBuilder, parserContext, "adviceChain"); + BeanDefinition parentBeanDefinition, ParserContext parserContext) { + configureAndSetAdviceChainIfPresent(adviceChainElement, txElement, parentBeanDefinition, parserContext, "adviceChain"); } @SuppressWarnings({ "rawtypes" }) public static void configureAndSetAdviceChainIfPresent(Element adviceChainElement, Element txElement, - BeanDefinitionBuilder parentBuilder, ParserContext parserContext, String propertyName) { - ManagedList adviceChain = configureAdviceChain(adviceChainElement, txElement, parentBuilder, parserContext); + BeanDefinition parentBeanDefinition, ParserContext parserContext, String propertyName) { + ManagedList adviceChain = configureAdviceChain(adviceChainElement, txElement, parentBeanDefinition, parserContext); if (adviceChain != null) { - parentBuilder.addPropertyValue(propertyName, adviceChain); + parentBeanDefinition.getPropertyValues().add(propertyName, adviceChain); } } @SuppressWarnings({ "rawtypes", "unchecked" }) public static ManagedList configureAdviceChain(Element adviceChainElement, Element txElement, - BeanDefinitionBuilder parentBuilder, ParserContext parserContext) { + BeanDefinition parentBeanDefinition, ParserContext parserContext) { ManagedList adviceChain = null; // Schema validation ensures txElement and adviceChainElement are mutually exclusive if (txElement != null) { @@ -361,7 +361,7 @@ public abstract class IntegrationNamespaceUtils { String localName = child.getLocalName(); if ("bean".equals(localName)) { BeanDefinitionHolder holder = parserContext.getDelegate().parseBeanDefinitionElement( - childElement, parentBuilder.getBeanDefinition()); + childElement, parentBeanDefinition); parserContext.registerBeanComponent(new BeanComponentDefinition(holder)); adviceChain.add(new RuntimeBeanReference(holder.getBeanName())); } @@ -371,7 +371,7 @@ public abstract class IntegrationNamespaceUtils { } else { BeanDefinition customBeanDefinition = parserContext.getDelegate().parseCustomElement( - childElement, parentBuilder.getBeanDefinition()); + childElement, parentBeanDefinition); if (customBeanDefinition == null) { parserContext.getReaderContext().error( "failed to parse custom element '" + localName + "'", childElement); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PollerParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PollerParser.java index 8f7b8eefaf..2833ca1514 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PollerParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PollerParser.java @@ -90,7 +90,7 @@ public class PollerParser extends AbstractBeanDefinitionParser { Element txElement = DomUtils.getChildElementByTagName(element, "transactional"); Element adviceChainElement = DomUtils.getChildElementByTagName(element, "advice-chain"); IntegrationNamespaceUtils.configureAndSetAdviceChainIfPresent(adviceChainElement, txElement, - metadataBuilder, parserContext); + metadataBuilder.getRawBeanDefinition(), parserContext); if (txElement != null){ IntegrationNamespaceUtils.setReferenceIfAttributeDefined(metadataBuilder, txElement, diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/SyslogTransformerParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/SyslogTransformerParserTests.java index 63bd59e076..a57dea7654 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/SyslogTransformerParserTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/SyslogTransformerParserTests.java @@ -34,6 +34,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author Gary Russell + * @author Artem Bilan * @since 2.2 * */ @@ -53,10 +54,10 @@ public class SyslogTransformerParserTests { Map map = (Map) out.receive(1000).getPayload(); assertNotNull(map); assertEquals(6, map.size()); - System.out.println(map); assertEquals(19, map.get(SyslogToMapTransformer.FACILITY)); assertEquals(5, map.get(SyslogToMapTransformer.SEVERITY)); - assertTrue(map.get(SyslogToMapTransformer.TIMESAMP) instanceof Date); + Object date = map.get(SyslogToMapTransformer.TIMESAMP); + assertTrue(date instanceof Date || date instanceof String); assertEquals("WEBERN", map.get(SyslogToMapTransformer.HOST)); assertEquals("TESTING[70729]", map.get(SyslogToMapTransformer.TAG)); assertEquals("TEST SYSLOG MESSAGE", map.get(SyslogToMapTransformer.MESSAGE)); diff --git a/spring-integration-core/src/test/java/org/springframework/integration/transformer/SysLogTransformerTests.java b/spring-integration-core/src/test/java/org/springframework/integration/transformer/SysLogTransformerTests.java index a7d5856063..da77625675 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/transformer/SysLogTransformerTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/transformer/SysLogTransformerTests.java @@ -25,6 +25,7 @@ import org.junit.Test; /** * @author Gary Russell + * @author Artem Bilan * @since 2.2 * */ @@ -36,10 +37,10 @@ public class SysLogTransformerTests { Map transformed = t.transformPayload( "<158>JUL 26 22:08:35 WEBERN TESTING[70729]: TEST SYSLOG MESSAGE".getBytes()); assertEquals(6, transformed.size()); -// System.out.println(transformed); assertEquals(19, transformed.get(SyslogToMapTransformer.FACILITY)); assertEquals(6, transformed.get(SyslogToMapTransformer.SEVERITY)); - assertTrue(transformed.get(SyslogToMapTransformer.TIMESAMP) instanceof Date); + Object date = transformed.get(SyslogToMapTransformer.TIMESAMP); + assertTrue(date instanceof Date || date instanceof String); assertEquals("WEBERN", transformed.get(SyslogToMapTransformer.HOST)); assertEquals("TESTING[70729]", transformed.get(SyslogToMapTransformer.TAG)); assertEquals("TEST SYSLOG MESSAGE", transformed.get(SyslogToMapTransformer.MESSAGE)); diff --git a/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/config/FtpOutboundGatewayParserTests-context.xml b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/config/FtpOutboundGatewayParserTests-context.xml index 60145b3ced..29a4d44180 100644 --- a/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/config/FtpOutboundGatewayParserTests-context.xml +++ b/spring-integration-ftp/src/test/java/org/springframework/integration/ftp/config/FtpOutboundGatewayParserTests-context.xml @@ -12,7 +12,7 @@ processor = new GroovyScriptExecutingMessageProcessor(scriptSource, scriptVariableGenerator); Object newResult = processor.processMessage(message); assertFalse(newResult.equals(result)); // make sure that we get different nanotime verifying that generateScriptVariables() is invoked @@ -153,7 +154,7 @@ public class GroovyScriptExecutingMessageProcessorTests { result = processor.processMessage(message); assertEquals("payload is foo, header is bar", result.toString()); } - + @Test public void testRefreshableScriptExecutionWithAlwaysRefresh() throws Exception { String script = "return \"payload is $payload, header is $headers.testHeader\""; @@ -178,26 +179,26 @@ public class GroovyScriptExecutingMessageProcessorTests { private static class TestResource extends AbstractResource { - private String script; + private volatile String script; private final String filename; - private long lastModified; + private volatile long lastModified; private TestResource(String script, String filename) { setScript(script); this.filename = filename; } - + public long lastModified() throws IOException { return lastModified; } - + public void setScript(String script) { - this.lastModified = System.currentTimeMillis(); + this.lastModified = System.nanoTime(); this.script = script; } - + public String getDescription() { return "test"; } @@ -208,8 +209,8 @@ public class GroovyScriptExecutingMessageProcessorTests { } public InputStream getInputStream() throws IOException { - return new ByteArrayInputStream(script.getBytes("UTF-8")); + return new ByteArrayInputStream(script.getBytes("UTF-8")); } - } + } } diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpOutboundGatewayParserTests.java b/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpOutboundGatewayParserTests.java index 37e15b8400..ffbe90640a 100644 --- a/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpOutboundGatewayParserTests.java +++ b/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpOutboundGatewayParserTests.java @@ -20,16 +20,20 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; import java.util.Map; import org.junit.Test; import org.junit.runner.RunWith; +import org.springframework.beans.BeansException; import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.expression.Expression; import org.springframework.expression.spel.standard.SpelExpression; import org.springframework.http.HttpMethod; @@ -51,6 +55,7 @@ import org.springframework.web.client.ResponseErrorHandler; /** * @author Mark Fisher * @author Gary Russell + * @author Artem Bilan */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration @@ -175,6 +180,20 @@ public class HttpOutboundGatewayParserTests { assertEquals(1, adviceCalled); } + @Test + public void testInt2718FailForGatewayRequestChannelAttribute() { + try { + new ClassPathXmlApplicationContext("HttpOutboundGatewayWithinChainTests-fail-context.xml", this.getClass()); + fail("Expected BeanDefinitionParsingException"); + } + catch (BeansException e) { + assertTrue(e instanceof BeanDefinitionParsingException); + assertTrue(e.getMessage().contains("'request-channel' attribute isn't allowed for a nested")); + } + } + + + public static class StubErrorHandler implements ResponseErrorHandler { public boolean hasError(ClientHttpResponse response) throws IOException { diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpOutboundGatewayWithinChainTests-fail-context.xml b/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpOutboundGatewayWithinChainTests-fail-context.xml new file mode 100644 index 0000000000..28619fb55d --- /dev/null +++ b/spring-integration-http/src/test/java/org/springframework/integration/http/config/HttpOutboundGatewayWithinChainTests-fail-context.xml @@ -0,0 +1,15 @@ + + + + + + + + diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/DelayerHandlerRescheduleIntegrationTests-context.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/DelayerHandlerRescheduleIntegrationTests-context.xml index 656bf70f91..ab97388e11 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/DelayerHandlerRescheduleIntegrationTests-context.xml +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/DelayerHandlerRescheduleIntegrationTests-context.xml @@ -28,7 +28,7 @@ diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/DelayerHandlerRescheduleIntegrationTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/DelayerHandlerRescheduleIntegrationTests.java index 388afda528..4469668a34 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/DelayerHandlerRescheduleIntegrationTests.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/DelayerHandlerRescheduleIntegrationTests.java @@ -133,7 +133,7 @@ public class DelayerHandlerRescheduleIntegrationTests { input.send(MessageBuilder.withPayload("test").build()); - Thread.sleep(30); + Thread.sleep(100); assertEquals(1, messageStore.messageGroupSize(delayerMessageGroupId)); @@ -141,12 +141,13 @@ public class DelayerHandlerRescheduleIntegrationTests { context.destroy(); context.refresh(); - assertTrue(RollbackTxSync.latch.await(2, TimeUnit.SECONDS)); + assertTrue(RollbackTxSync.latch.await(20, TimeUnit.SECONDS)); //On transaction rollback the delayed Message should remain in the persistent MessageStore assertEquals(1, messageStore.messageGroupSize(delayerMessageGroupId)); } + @SuppressWarnings("unused") private static class TestJdbcMessageStore extends JdbcMessageStore { private TestJdbcMessageStore() { @@ -156,6 +157,7 @@ public class DelayerHandlerRescheduleIntegrationTests { } + @SuppressWarnings("unused") private static class ExceptionMessageHandler implements MessageHandler { public void handleMessage(Message message) throws MessagingException { diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcMessageStoreChannelIntegrationTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcMessageStoreChannelIntegrationTests.java index 3efc40244d..ae7e447738 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcMessageStoreChannelIntegrationTests.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcMessageStoreChannelIntegrationTests.java @@ -1,11 +1,11 @@ /* - * Copyright 2002-2011 the original author or authors. - * + * Copyright 2002-2012 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. @@ -41,6 +41,14 @@ import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; import org.springframework.util.StopWatch; +/** + * @author Dave Syer + * @author Mark Fisher + * @author Gary Russell + * @author Oleg Zhurakousky + * @author Gunnar Hillert + * @author Artem Bilan + */ @ContextConfiguration @RunWith(SpringJUnit4ClassRunner.class) public class JdbcMessageStoreChannelIntegrationTests { @@ -60,6 +68,7 @@ public class JdbcMessageStoreChannelIntegrationTests { @Before public void clear() { + Service.reset(1); for (MessageGroup group : messageStore) { messageStore.removeMessageGroup(group.getGroupId()); } @@ -67,7 +76,6 @@ public class JdbcMessageStoreChannelIntegrationTests { @Test public void testSendAndActivate() throws Exception { - Service.reset(1); input.send(new GenericMessage("foo")); Service.await(1000); assertEquals(1, Service.messages.size()); @@ -75,7 +83,6 @@ public class JdbcMessageStoreChannelIntegrationTests { @Test public void testSendAndActivateWithRollback() throws Exception { - Service.reset(1); Service.fail = true; input.send(new GenericMessage("foo")); Service.await(1000); @@ -99,12 +106,10 @@ public class JdbcMessageStoreChannelIntegrationTests { }); } - @Test - @Repeat(10) + @Test + @Repeat(2) public void testTransactionalSendAndReceive() throws Exception { - Service.reset(1); - boolean result = new TransactionTemplate(transactionManager).execute(new TransactionCallback() { public Boolean doInTransaction(TransactionStatus status) { @@ -153,14 +158,13 @@ public class JdbcMessageStoreChannelIntegrationTests { } Thread.sleep(50); } - + assertEquals(1, Service.messages.size()); } @Test public void testSameTransactionSendAndReceive() throws Exception { - Service.reset(1); final StopWatch stopWatch = new StopWatch(); DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition(); @@ -213,7 +217,7 @@ public class JdbcMessageStoreChannelIntegrationTests { private static List messages = new CopyOnWriteArrayList(); - private static CountDownLatch latch = new CountDownLatch(0); + private static CountDownLatch latch; public static void reset(int count) { fail = false; diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcMessageStoreTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcMessageStoreTests.java index f06557f91c..eb13322028 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcMessageStoreTests.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/JdbcMessageStoreTests.java @@ -55,6 +55,13 @@ import static org.junit.Assert.assertTrue; import static org.springframework.integration.test.matcher.PayloadAndHeaderMatcher.sameExceptIgnorableHeaders; +/** + * @author Dave Syer + * @author Mark Fisher + * @author Oleg Zhurakousky + * @author Gunnar Hillert + * @author Artem Bilan + */ @ContextConfiguration @RunWith(SpringJUnit4ClassRunner.class) public class JdbcMessageStoreTests { @@ -88,17 +95,17 @@ public class JdbcMessageStoreTests { assertNotNull(result.getHeaders().get(JdbcMessageStore.SAVED_KEY)); assertNotNull(result.getHeaders().get(JdbcMessageStore.CREATED_DATE_KEY)); } - + @Test @Transactional - public void testWithMessageHistory() throws Exception{ - + public void testWithMessageHistory() throws Exception{ + Message message = new GenericMessage("Hello"); DirectChannel fooChannel = new DirectChannel(); fooChannel.setBeanName("fooChannel"); DirectChannel barChannel = new DirectChannel(); barChannel.setBeanName("barChannel"); - + message = MessageHistory.write(message, fooChannel); message = MessageHistory.write(message, barChannel); messageStore.addMessage(message); @@ -226,7 +233,7 @@ public class JdbcMessageStoreTests { MessageGroup group = messageStore.getMessageGroup(groupId); assertEquals(0, group.size()); } - + @Test @Transactional public void testCompleteMessageGroup() throws Exception { @@ -238,7 +245,7 @@ public class JdbcMessageStoreTests { assertTrue(group.isComplete()); assertEquals(1, group.size()); } - + @Test @Transactional public void testUpdateLastReleasedSequence() throws Exception { @@ -272,10 +279,10 @@ public class JdbcMessageStoreTests { @Transactional public void testOrderInMessageGroup() throws Exception { String groupId = "X"; - Message message = MessageBuilder.withPayload("foo").setCorrelationId(groupId).build(); - messageStore.addMessageToGroup(groupId, message); - message = MessageBuilder.withPayload("bar").setCorrelationId(groupId).build(); - messageStore.addMessageToGroup(groupId, message); + + messageStore.addMessageToGroup(groupId, MessageBuilder.withPayload("foo").setCorrelationId(groupId).build()); + Thread.sleep(1); + messageStore.addMessageToGroup(groupId, MessageBuilder.withPayload("bar").setCorrelationId(groupId).build()); MessageGroup group = messageStore.getMessageGroup(groupId); assertEquals(2, group.size()); assertEquals("foo", messageStore.pollMessageFromGroup(groupId).getPayload()); @@ -303,7 +310,7 @@ public class JdbcMessageStoreTests { group = messageStore.getMessageGroup(groupId); assertEquals(0, group.size()); } - + @Test @Transactional public void testExpireMessageGroupOnIdleOnly() throws Exception { @@ -334,26 +341,31 @@ public class JdbcMessageStoreTests { @Transactional public void testMessagePollingFromTheGroup() throws Exception { String groupId = "X"; - Message message = MessageBuilder.withPayload("foo").setCorrelationId(groupId).build(); - messageStore.addMessageToGroup(groupId, message); + messageStore.addMessageToGroup(groupId, MessageBuilder.withPayload("foo").setCorrelationId(groupId).build()); + Thread.sleep(1); messageStore.addMessageToGroup(groupId, MessageBuilder.withPayload("bar").setCorrelationId(groupId).build()); + Thread.sleep(1); messageStore.addMessageToGroup(groupId, MessageBuilder.withPayload("baz").setCorrelationId(groupId).build()); + messageStore.addMessageToGroup("Y", MessageBuilder.withPayload("barA").setCorrelationId(groupId).build()); + Thread.sleep(1); messageStore.addMessageToGroup("Y", MessageBuilder.withPayload("bazA").setCorrelationId(groupId).build()); + MessageGroup group = messageStore.getMessageGroup("X"); assertEquals(3, group.size()); Message message1 = messageStore.pollMessageFromGroup("X"); assertNotNull(message1); assertEquals("foo", message1.getPayload()); - System.out.println("Polled Message" + message1); + group = messageStore.getMessageGroup("X"); assertEquals(2, group.size()); Message message2 = messageStore.pollMessageFromGroup("X"); assertNotNull(message2); assertEquals("bar", message2.getPayload()); + group = messageStore.getMessageGroup("X"); assertEquals(1, group.size()); } diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithNamespaceIntegrationTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithNamespaceIntegrationTests.java index 5ea654876c..26b587d096 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithNamespaceIntegrationTests.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/StoredProcOutboundGatewayWithNamespaceIntegrationTests.java @@ -28,6 +28,7 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -54,7 +55,7 @@ import javax.sql.DataSource; public class StoredProcOutboundGatewayWithNamespaceIntegrationTests { @Autowired - DataSource dataSource; + JdbcTemplate jdbcTemplate; @Autowired private Consumer consumer; @@ -68,6 +69,11 @@ public class StoredProcOutboundGatewayWithNamespaceIntegrationTests { @Autowired PollableChannel replyChannel; + @Before + public void setUp() { + this.jdbcTemplate.execute("delete from USERS"); + } + @Test public void test() throws Exception { @@ -97,10 +103,6 @@ public class StoredProcOutboundGatewayWithNamespaceIntegrationTests { @Test //INT-1029 public void testStoredProcOutboundGatewayInsideChain() throws Exception { - JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); - - jdbcTemplate.execute("delete from USERS"); - Message requestMessage = MessageBuilder.withPayload(new User("myUsername", "myPassword", "myEmail")).build(); storedProcOutboundGatewayInsideChain.send(requestMessage); diff --git a/spring-integration-jdbc/src/test/resources/derby-stored-procedures-setup-context.xml b/spring-integration-jdbc/src/test/resources/derby-stored-procedures-setup-context.xml index bf013ecc16..34c4f880ee 100644 --- a/spring-integration-jdbc/src/test/resources/derby-stored-procedures-setup-context.xml +++ b/spring-integration-jdbc/src/test/resources/derby-stored-procedures-setup-context.xml @@ -2,13 +2,8 @@ + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> @@ -17,6 +12,10 @@ + + + + diff --git a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundGatewayParserTests-context.xml b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundGatewayParserTests-context.xml index 95484539ce..db8f9ae8e1 100644 --- a/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundGatewayParserTests-context.xml +++ b/spring-integration-sftp/src/test/java/org/springframework/integration/sftp/config/SftpOutboundGatewayParserTests-context.xml @@ -12,7 +12,7 @@ + + + + + + + + + + + + + + + diff --git a/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/config/TestSendingMessageHandlerParserTests.java b/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/config/TestSendingMessageHandlerParserTests.java index d8a50ea46d..b94e7457b8 100644 --- a/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/config/TestSendingMessageHandlerParserTests.java +++ b/spring-integration-twitter/src/test/java/org/springframework/integration/twitter/config/TestSendingMessageHandlerParserTests.java @@ -18,8 +18,12 @@ package org.springframework.integration.twitter.config; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import org.junit.Test; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.integration.Message; @@ -33,6 +37,7 @@ import org.springframework.integration.twitter.outbound.DirectMessageSendingMess /** * @author Oleg Zhurakousky * @author Gary Russell + * @author Artem Bilan * @since 2.0 */ public class TestSendingMessageHandlerParserTests { @@ -56,6 +61,20 @@ public class TestSendingMessageHandlerParserTests { assertEquals(2, adviceCalled); } + @Test + public void testInt2718FailForOutboundAdapterWithRequestHandlerAdviceChainWithinChainConfig() { + try { + new ClassPathXmlApplicationContext("OutboundAdapterWithRHACWithinChain-fail-context.xml", this.getClass()); + fail("Expected BeanDefinitionParsingException"); + } + catch (BeansException e) { + assertTrue(e instanceof BeanDefinitionParsingException); + assertTrue(e.getMessage().contains("'request-handler-advice-chain' isn't allowed " + + "for 'twitter:outbound-channel-adapter' within a , because its Handler isn't an AbstractReplyProducingMessageHandler")); + } + } + + public static class FooAdvice extends AbstractRequestHandlerAdvice { @Override diff --git a/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests.java b/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests.java index 849f9f9db8..adce8d587d 100644 --- a/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests.java +++ b/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/WebServiceOutboundGatewayParserTests.java @@ -28,6 +28,7 @@ import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.integration.Message; +import org.springframework.integration.MessageChannel; import org.springframework.integration.core.MessageHandler; import org.springframework.integration.endpoint.AbstractEndpoint; import org.springframework.integration.endpoint.EventDrivenConsumer; @@ -52,6 +53,7 @@ import org.springframework.ws.transport.WebServiceMessageSender; * @author Oleg Zhurakousky * @author Gunnar Hillert * @author Gary Russell + * @author Artem Bilan */ public class WebServiceOutboundGatewayParserTests { @@ -367,6 +369,7 @@ public class WebServiceOutboundGatewayParserTests { @Test public void advised() { + adviceCalled = 0; ApplicationContext context = new ClassPathXmlApplicationContext( "simpleWebServiceOutboundGatewayParserTests.xml", this.getClass()); AbstractEndpoint endpoint = (AbstractEndpoint) context.getBean("gatewayWithAdvice"); @@ -376,6 +379,16 @@ public class WebServiceOutboundGatewayParserTests { assertEquals(1, adviceCalled); } + @Test + public void testInt2718AdvisedInsideTheChain() { + adviceCalled = 0; + ApplicationContext context = new ClassPathXmlApplicationContext( + "simpleWebServiceOutboundGatewayParserTests.xml", this.getClass()); + MessageChannel channel = context.getBean("gatewayWithAdviceInsideAChain", MessageChannel.class); + channel.send(new GenericMessage("foo")); + assertEquals(1, adviceCalled); + } + @Test(expected = BeanDefinitionParsingException.class) public void invalidGatewayWithBothUriAndDestinationProvider() { new ClassPathXmlApplicationContext("invalidGatewayWithBothUriAndDestinationProvider.xml", this.getClass()); diff --git a/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/simpleWebServiceOutboundGatewayParserTests.xml b/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/simpleWebServiceOutboundGatewayParserTests.xml index d991f24cf9..d28939bad0 100644 --- a/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/simpleWebServiceOutboundGatewayParserTests.xml +++ b/spring-integration-ws/src/test/java/org/springframework/integration/ws/config/simpleWebServiceOutboundGatewayParserTests.xml @@ -102,14 +102,25 @@ request-channel="inputChannel" destination-provider="destinationProvider" /> - + + - + + + + + + + + + + diff --git a/src/reference/docbook/handler-advice.xml b/src/reference/docbook/handler-advice.xml index 89bb7ec1e3..6ff7b2497e 100644 --- a/src/reference/docbook/handler-advice.xml +++ b/src/reference/docbook/handler-advice.xml @@ -43,6 +43,22 @@ will not apply to further actions taken downstream after the reply is sent to the nextChannel. The scope of the advice is limited to the endpoint itself. + + + At this time, you cannot advise an entire <chain/> of endpoints. The schema does not allow + a <request-handler-advice-chain/> as a child element of the chain itself. + + + However, a <request-handler-advice-chain/> can be added to individual reply-producing endpoints + within a <chain/> element. + An exception is that, in a chain that produces no reply, because the last element in the chain is an + outbound-channel-adapter, that last element cannot be advised. If you + need to advise such an element, it must be moved outside of the chain (with the + output-channel of the chain being the input-channel of + the adapter. The adapter can then be advised as normal. For chains that produce a reply, every child + element can be advised. + +
Provided Advice Classes