Merge pull request #592 from artembilan/INT-2718

This commit is contained in:
Gary Russell
2012-09-10 16:14:25 -04:00
27 changed files with 300 additions and 98 deletions

View File

@@ -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

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:amqp="http://www.springframework.org/schema/integration/amqp"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="http://www.springframework.org/schema/integration/amqp http://www.springframework.org/schema/integration/amqp/spring-integration-amqp.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<int:chain input-channel="inputChannel">
<amqp:outbound-channel-adapter channel="someChannel"/>
</int:chain>
</beans>

View File

@@ -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 <chain/>) 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);

View File

@@ -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 <chain/>", 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 <chain/>, because its Handler " +
"isn't an AbstractReplyProducingMessageHandler", element);
}
}
return builder.getBeanDefinition();
}
/**

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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,

View File

@@ -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));

View File

@@ -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<String, ?> 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));

View File

@@ -12,7 +12,7 @@
</bean>
<int-ftp:outbound-gateway id="gateway1"
local-directory="/tmp"
local-directory="local-test-dir"
session-factory="sf"
request-channel="inbound1"
reply-channel="outbound"
@@ -29,7 +29,7 @@
/>
<int-ftp:outbound-gateway id="gateway2"
local-directory="/tmp"
local-directory="local-test-dir"
session-factory="sf"
request-channel="inbound2"
reply-channel="outbound"

View File

@@ -39,6 +39,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Gary Russell
* @author Gunnar Hillert
* @author Artem Bilan
*
* @since 2.1
*
@@ -62,7 +63,7 @@ public class FtpOutboundGatewayParserTests {
assertEquals("X", TestUtils.getPropertyValue(gateway, "remoteFileSeparator"));
assertNotNull(TestUtils.getPropertyValue(gateway, "sessionFactory"));
assertNotNull(TestUtils.getPropertyValue(gateway, "outputChannel"));
assertEquals(new File("/tmp"), TestUtils.getPropertyValue(gateway, "localDirectory"));
assertEquals(new File("local-test-dir"), TestUtils.getPropertyValue(gateway, "localDirectory"));
assertFalse((Boolean) TestUtils.getPropertyValue(gateway, "autoCreateLocalDirectory"));
assertNotNull(TestUtils.getPropertyValue(gateway, "filter"));
assertEquals("ls", TestUtils.getPropertyValue(gateway, "command"));
@@ -83,7 +84,7 @@ public class FtpOutboundGatewayParserTests {
assertNotNull(TestUtils.getPropertyValue(gateway, "sessionFactory"));
assertTrue(TestUtils.getPropertyValue(gateway, "sessionFactory") instanceof CachingSessionFactory);
assertNotNull(TestUtils.getPropertyValue(gateway, "outputChannel"));
assertEquals(new File("/tmp"), TestUtils.getPropertyValue(gateway, "localDirectory"));
assertEquals(new File("local-test-dir"), TestUtils.getPropertyValue(gateway, "localDirectory"));
assertFalse((Boolean) TestUtils.getPropertyValue(gateway, "autoCreateLocalDirectory"));
assertEquals("get", TestUtils.getPropertyValue(gateway, "command"));
@SuppressWarnings("unchecked")

View File

@@ -1,5 +1,5 @@
/*
* 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.
@@ -42,6 +42,7 @@ import org.springframework.test.annotation.Repeat;
* @author Mark Fisher
* @author Dave Syer
* @author Oleg Zhurakousky
* @author Artem Bilan
* @since 2.0
*/
public class GroovyScriptExecutingMessageProcessorTests {
@@ -63,7 +64,7 @@ public class GroovyScriptExecutingMessageProcessorTests {
Object result = processor.processMessage(message);
assertEquals("payload is foo, header is bar"+count, result.toString());
}
@Test
public void testSimpleExecutionWithScriptVariableGenerator() throws Exception {
int count = countHolder.getAndIncrement();
@@ -82,7 +83,7 @@ public class GroovyScriptExecutingMessageProcessorTests {
}
}
for (int i = 0; i < 5; i++) {
ScriptVariableGenerator scriptVariableGenerator = new CustomScriptVariableGenerator();
ScriptVariableGenerator scriptVariableGenerator = new CustomScriptVariableGenerator();
MessageProcessor<Object> 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"));
}
}
}
}

View File

@@ -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 {

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
xmlns="http://www.springframework.org/schema/integration/http"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:si="http://www.springframework.org/schema/integration"
xsi:schemaLocation="http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<si:chain input-channel="httpOutboundGatewayWithinChain">
<outbound-gateway url="http://test.org" request-channel="someRequestChannel"/>
</si:chain>
</beans:beans>

View File

@@ -28,7 +28,7 @@
<delayer id="transactionalDelayer"
input-channel="transactionalDelayerInput"
output-channel="transactionalDelayerOutput"
default-delay="10"
default-delay="50"
message-store="messageStore">
<transactional/>
</delayer>

View File

@@ -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 {

View File

@@ -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<String>("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<String>("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<Boolean>() {
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<String> messages = new CopyOnWriteArrayList<String>();
private static CountDownLatch latch = new CountDownLatch(0);
private static CountDownLatch latch;
public static void reset(int count) {
fail = false;

View File

@@ -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<String>("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<String> 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<String> 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());
}

View File

@@ -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<User> requestMessage = MessageBuilder.withPayload(new User("myUsername", "myPassword", "myEmail")).build();
storedProcOutboundGatewayInsideChain.send(requestMessage);

View File

@@ -2,13 +2,8 @@
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<jdbc:embedded-database id="dataSource" type="DERBY"/>
@@ -17,6 +12,10 @@
<jdbc:script location="classpath:derby-stored-procedures.sql"/>
</jdbc:initialize-database>
<bean class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />

View File

@@ -12,7 +12,7 @@
</bean>
<int-sftp:outbound-gateway id="gateway1"
local-directory="/tmp"
local-directory="local-test-dir"
session-factory="sf"
request-channel="inbound1"
reply-channel="outbound"
@@ -29,7 +29,7 @@
/>
<int-sftp:outbound-gateway id="gateway2"
local-directory="/tmp"
local-directory="local-test-dir"
session-factory="sf"
request-channel="inbound2"
reply-channel="outbound"
@@ -44,7 +44,7 @@
/>
<int-sftp:outbound-gateway id="advised"
local-directory="/tmp"
local-directory="local-test-dir"
session-factory="sf"
request-channel="inbound2"
reply-channel="outbound"

View File

@@ -39,6 +39,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Gary Russell
* @author Gunnar Hillert
* @author Artem Bilan
*
* @since 2.1
*
@@ -65,7 +66,7 @@ public class SftpOutboundGatewayParserTests {
assertEquals("X", TestUtils.getPropertyValue(gateway, "remoteFileSeparator"));
assertNotNull(TestUtils.getPropertyValue(gateway, "sessionFactory"));
assertNotNull(TestUtils.getPropertyValue(gateway, "outputChannel"));
assertEquals(new File("/tmp"), TestUtils.getPropertyValue(gateway, "localDirectory"));
assertEquals(new File("local-test-dir"), TestUtils.getPropertyValue(gateway, "localDirectory"));
assertFalse((Boolean) TestUtils.getPropertyValue(gateway, "autoCreateLocalDirectory"));
assertNotNull(TestUtils.getPropertyValue(gateway, "filter"));
assertEquals("ls", TestUtils.getPropertyValue(gateway, "command"));
@@ -86,7 +87,7 @@ public class SftpOutboundGatewayParserTests {
assertNotNull(TestUtils.getPropertyValue(gateway, "sessionFactory"));
assertTrue(TestUtils.getPropertyValue(gateway, "sessionFactory") instanceof CachingSessionFactory);
assertNotNull(TestUtils.getPropertyValue(gateway, "outputChannel"));
assertEquals(new File("/tmp"), TestUtils.getPropertyValue(gateway, "localDirectory"));
assertEquals(new File("local-test-dir"), TestUtils.getPropertyValue(gateway, "localDirectory"));
assertFalse((Boolean) TestUtils.getPropertyValue(gateway, "autoCreateLocalDirectory"));
assertEquals("get", TestUtils.getPropertyValue(gateway, "command"));
@SuppressWarnings("unchecked")

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:twitter="http://www.springframework.org/schema/integration/twitter"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/twitter http://www.springframework.org/schema/integration/twitter/spring-integration-twitter.xsd">
<beans:bean id="twitter" class="org.springframework.social.twitter.api.impl.TwitterTemplate"/>
<chain input-channel="inputChannel">
<twitter:outbound-channel-adapter twitter-template="twitter">
<twitter:request-handler-advice-chain>
<beans:bean class="org.springframework.integration.twitter.config.TestSendingMessageHandlerParserTests$FooAdvice" />
</twitter:request-handler-advice-chain>
</twitter:outbound-channel-adapter>
</chain>
</beans:beans>

View File

@@ -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 <chain/>, because its Handler isn't an AbstractReplyProducingMessageHandler"));
}
}
public static class FooAdvice extends AbstractRequestHandlerAdvice {
@Override

View File

@@ -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<String>("foo"));
assertEquals(1, adviceCalled);
}
@Test(expected = BeanDefinitionParsingException.class)
public void invalidGatewayWithBothUriAndDestinationProvider() {
new ClassPathXmlApplicationContext("invalidGatewayWithBothUriAndDestinationProvider.xml", this.getClass());

View File

@@ -102,14 +102,25 @@
request-channel="inputChannel"
destination-provider="destinationProvider" />
<ws:outbound-gateway id="gatewayWithAdvice"
<bean id="fooAdvice" class="org.springframework.integration.ws.config.WebServiceOutboundGatewayParserTests$FooAdvice"/>
<ws:outbound-gateway id="gatewayWithAdvice"
request-channel="inputChannel"
destination-provider="destinationProvider">
<ws:request-handler-advice-chain>
<bean class="org.springframework.integration.ws.config.WebServiceOutboundGatewayParserTests$FooAdvice"/>
<ref bean="fooAdvice"/>
</ws:request-handler-advice-chain>
</ws:outbound-gateway>
<si:chain input-channel="gatewayWithAdviceInsideAChain">
<ws:outbound-gateway destination-provider="destinationProvider">
<ws:request-handler-advice-chain>
<ref bean="fooAdvice"/>
</ws:request-handler-advice-chain>
</ws:outbound-gateway>
</si:chain>
<bean id="sourceExtractor" class="org.springframework.integration.ws.config.StubSourceExtractor"/>
<bean id="requestCallback" class="org.springframework.integration.ws.config.StubWebServiceMessageCallback"/>

View File

@@ -43,6 +43,22 @@
will not apply to further actions taken downstream after the reply is sent to the
<emphasis>nextChannel</emphasis>. The scope of the advice is limited to the endpoint itself.
</para>
<important>
<para>
At this time, you cannot advise an entire &lt;chain/&gt; of endpoints. The schema does not allow
a &lt;request-handler-advice-chain/&gt; as a child element of the chain itself.
</para>
<para>
However, a &lt;request-handler-advice-chain/&gt; can be added to individual reply-producing endpoints
<emphasis>within</emphasis> a &lt;chain/&gt; element.
An exception is that, in a chain that produces no reply, because the last element in the chain is an
<emphasis>outbound-channel-adapter</emphasis>, that <emphasis>last</emphasis> element cannot be advised. If you
need to advise such an element, it must be moved outside of the chain (with the
<emphasis>output-channel</emphasis> of the chain being the <emphasis>input-channel</emphasis> of
the adapter. The adapter can then be advised as normal. For chains that produce a reply, every child
element can be advised.
</para>
</important>
<section id="advice-classes">
<title>Provided Advice Classes</title>
<para>