diff --git a/spring-integration-amqp/src/main/resources/org/springframework/integration/amqp/config/spring-integration-amqp-3.0.xsd b/spring-integration-amqp/src/main/resources/org/springframework/integration/amqp/config/spring-integration-amqp-3.0.xsd
index 7d2b3db129..90089d4475 100644
--- a/spring-integration-amqp/src/main/resources/org/springframework/integration/amqp/config/spring-integration-amqp-3.0.xsd
+++ b/spring-integration-amqp/src/main/resources/org/springframework/integration/amqp/config/spring-integration-amqp-3.0.xsd
@@ -193,6 +193,9 @@
which itself is a Map.
This can only be provided if the 'header-mapper' reference is not being set directly. The values in
this list can also be simple patterns to be matched against the header names (e.g. "foo*" or "*foo").
+ A special token 'STANDARD_REPLY_HEADERS' represents all the standard AMQP headers (replyTo, correlationId etc);
+ it is included by default. If you wish to add your own headers, you must also include this token if you wish the
+ standard headers to also be mapped.
]]>
@@ -243,6 +246,9 @@
which itself is a Map.
This can only be provided if the 'header-mapper' reference is not being set directly. The values in
this list can also be simple patterns to be matched against the header names (e.g. "foo*" or "*foo").
+ A special token 'STANDARD_REPLY_HEADERS' represents all the standard AMQP headers (replyTo, correlationId etc);
+ it is included by default. If you wish to add your own headers, you must also include this token if you wish the
+ standard headers to also be mapped.
]]>
@@ -418,9 +424,15 @@ The order for this consumer when multiple consumers are registered thereby enabl
+
-
+
@@ -431,6 +443,9 @@ The order for this consumer when multiple consumers are registered thereby enabl
Comma-separated list of names of AMQP Headers to be mapped from the AMQP request into the MessageHeaders.
This can only be provided if the 'header-mapper' reference is not being set directly. The values in
this list can also be simple patterns to be matched against the header names (e.g. "foo*" or "*foo").
+A special token 'STANDARD_REQUEST_HEADERS' represents all the standard AMQP headers (replyTo, correlationId etc);
+it is included by default. If you wish to add your own headers, you must also include this token if you wish the
+standard headers to also be mapped.
]]>
@@ -478,9 +493,15 @@ property set to TRUE.
+
-
+
@@ -491,6 +512,9 @@ property set to TRUE.
Comma-separated list of names of AMQP Headers to be mapped from the AMQP request into the MessageHeaders.
This can only be provided if the 'header-mapper' reference is not being set directly. The values in
this list can also be simple patterns to be matched against the header names (e.g. "foo*" or "*foo").
+A special token 'STANDARD_REQUEST_HEADERS' represents all the standard AMQP headers (replyTo, correlationId etc);
+it is included by default. If you wish to add your own headers, you must also include this token if you wish the
+standard headers to also be mapped.
]]>
diff --git a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpInboundChannelAdapterParserTests-headerMapper-fail-context.xml b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpInboundChannelAdapterParserTests-headerMapper-fail-context.xml
new file mode 100644
index 0000000000..f93bb71482
--- /dev/null
+++ b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpInboundChannelAdapterParserTests-headerMapper-fail-context.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
diff --git a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpInboundChannelAdapterParserTests.java b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpInboundChannelAdapterParserTests.java
index 0ce0b8844d..2844f021f0 100644
--- a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpInboundChannelAdapterParserTests.java
+++ b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpInboundChannelAdapterParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2013 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.
@@ -22,8 +22,11 @@ import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer;
+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.amqp.AmqpHeaders;
import org.springframework.integration.amqp.inbound.AmqpInboundChannelAdapter;
import org.springframework.integration.channel.DirectChannel;
@@ -35,9 +38,11 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
/**
* @author Mark Fisher
+ * @author Artem Bilan
* @since 2.1
*/
@ContextConfiguration
@@ -63,12 +68,12 @@ public class AmqpInboundChannelAdapterParserTests {
assertEquals(Boolean.FALSE, TestUtils.getPropertyValue(adapter, "autoStartup"));
assertEquals(123, TestUtils.getPropertyValue(adapter, "phase"));
}
-
+
@Test
public void withHeaderMapperStandardAndCustomHeaders() {
AmqpInboundChannelAdapter adapter = context.getBean("withHeaderMapperStandardAndCustomHeaders", AmqpInboundChannelAdapter.class);
-
- AbstractMessageListenerContainer mlc =
+
+ AbstractMessageListenerContainer mlc =
TestUtils.getPropertyValue(adapter, "messageListenerContainer", AbstractMessageListenerContainer.class);
MessageListener listener = TestUtils.getPropertyValue(mlc, "messageListener", MessageListener.class);
MessageProperties amqpProperties = new MessageProperties();
@@ -90,12 +95,12 @@ public class AmqpInboundChannelAdapterParserTests {
assertNotNull(siMessage.getHeaders().get(AmqpHeaders.APP_ID));
assertNotNull(siMessage.getHeaders().get(AmqpHeaders.CONTENT_TYPE));
}
-
+
@Test
public void withHeaderMapperOnlyCustomHeaders() {
AmqpInboundChannelAdapter adapter = context.getBean("withHeaderMapperOnlyCustomHeaders", AmqpInboundChannelAdapter.class);
-
- AbstractMessageListenerContainer mlc =
+
+ AbstractMessageListenerContainer mlc =
TestUtils.getPropertyValue(adapter, "messageListenerContainer", AbstractMessageListenerContainer.class);
MessageListener listener = TestUtils.getPropertyValue(mlc, "messageListener", MessageListener.class);
MessageProperties amqpProperties = new MessageProperties();
@@ -117,12 +122,12 @@ public class AmqpInboundChannelAdapterParserTests {
assertNull(siMessage.getHeaders().get(AmqpHeaders.APP_ID));
assertNull(siMessage.getHeaders().get(AmqpHeaders.CONTENT_TYPE));
}
-
+
@Test
public void withHeaderMapperNothingToMap() {
AmqpInboundChannelAdapter adapter = context.getBean("withHeaderMapperNothingToMap", AmqpInboundChannelAdapter.class);
-
- AbstractMessageListenerContainer mlc =
+
+ AbstractMessageListenerContainer mlc =
TestUtils.getPropertyValue(adapter, "messageListenerContainer", AbstractMessageListenerContainer.class);
MessageListener listener = TestUtils.getPropertyValue(mlc, "messageListener", MessageListener.class);
MessageProperties amqpProperties = new MessageProperties();
@@ -135,7 +140,7 @@ public class AmqpInboundChannelAdapterParserTests {
amqpProperties.setHeader("bar", "bar");
Message amqpMessage = new Message("hello".getBytes(), amqpProperties);
listener.onMessage(amqpMessage);
-
+
QueueChannel requestChannel = context.getBean("requestChannel", QueueChannel.class);
org.springframework.integration.Message> siMessage = requestChannel.receive(0);
assertNull(siMessage.getHeaders().get("foo"));
@@ -145,12 +150,12 @@ public class AmqpInboundChannelAdapterParserTests {
assertNull(siMessage.getHeaders().get(AmqpHeaders.APP_ID));
assertNull(siMessage.getHeaders().get(AmqpHeaders.CONTENT_TYPE));
}
-
+
@Test
public void withHeaderMapperDefaultMapping() {
AmqpInboundChannelAdapter adapter = context.getBean("withHeaderMapperDefaultMapping", AmqpInboundChannelAdapter.class);
-
- AbstractMessageListenerContainer mlc =
+
+ AbstractMessageListenerContainer mlc =
TestUtils.getPropertyValue(adapter, "messageListenerContainer", AbstractMessageListenerContainer.class);
MessageListener listener = TestUtils.getPropertyValue(mlc, "messageListener", MessageListener.class);
MessageProperties amqpProperties = new MessageProperties();
@@ -172,4 +177,16 @@ public class AmqpInboundChannelAdapterParserTests {
assertNotNull(siMessage.getHeaders().get(AmqpHeaders.APP_ID));
assertNotNull(siMessage.getHeaders().get(AmqpHeaders.CONTENT_TYPE));
}
+
+ @Test
+ public void testInt2971HeaderMapperAndMappedHeadersExclusivity() {
+ try {
+ new ClassPathXmlApplicationContext("AmqpInboundChannelAdapterParserTests-headerMapper-fail-context.xml", this.getClass());
+ }
+ catch (BeanDefinitionParsingException e) {
+ assertTrue(e.getMessage().startsWith("Configuration problem: The 'header-mapper' attribute " +
+ "is mutually exclusive with 'mapped-request-headers' or 'mapped-reply-headers'"));
+ }
+ }
+
}
diff --git a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpInboundGatewayParserTests-headerMapper-fail-context.xml b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpInboundGatewayParserTests-headerMapper-fail-context.xml
new file mode 100644
index 0000000000..0ef15ed537
--- /dev/null
+++ b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpInboundGatewayParserTests-headerMapper-fail-context.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
diff --git a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpInboundGatewayParserTests.java b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpInboundGatewayParserTests.java
index 54ec93e55f..439ce344dd 100644
--- a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpInboundGatewayParserTests.java
+++ b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpInboundGatewayParserTests.java
@@ -16,6 +16,10 @@
package org.springframework.integration.amqp.config;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
import java.lang.reflect.Field;
import org.junit.Test;
@@ -32,7 +36,9 @@ import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.amqp.support.converter.SimpleMessageConverter;
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.MessageChannel;
import org.springframework.integration.MessagingException;
import org.springframework.integration.amqp.inbound.AmqpInboundGateway;
@@ -44,13 +50,10 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.ReflectionUtils;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
-
/**
* @author Mark Fisher
* @author Gunnar Hillert
- *
+ * @author Artem Bilan
* @since 2.1
*/
@ContextConfiguration
@@ -130,6 +133,17 @@ public class AmqpInboundGatewayParserTests {
Mockito.any(Message.class), Mockito.any(CorrelationData.class));
}
+ @Test
+ public void testInt2971HeaderMapperAndMappedHeadersExclusivity() {
+ try {
+ new ClassPathXmlApplicationContext("AmqpInboundGatewayParserTests-headerMapper-fail-context.xml", this.getClass());
+ }
+ catch (BeanDefinitionParsingException e) {
+ assertTrue(e.getMessage().startsWith("Configuration problem: The 'header-mapper' attribute " +
+ "is mutually exclusive with 'mapped-request-headers' or 'mapped-reply-headers'"));
+ }
+ }
+
private static class TestConverter extends SimpleMessageConverter {}
}
diff --git a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests-context.xml b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests-context.xml
index 563c869c6c..daf07d34ad 100644
--- a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests-context.xml
+++ b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests-context.xml
@@ -25,6 +25,14 @@
exchange-name="outboundchanneladapter.test.1"
mapped-request-headers="foo*"/>
+
+
+
+
diff --git a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests-headerMapper-fail-context.xml b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests-headerMapper-fail-context.xml
new file mode 100644
index 0000000000..3b263d34a8
--- /dev/null
+++ b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundChannelAdapterParserTests-headerMapper-fail-context.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
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 27e8181fe6..c6ea61a3a5 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
@@ -45,6 +45,7 @@ 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.annotation.Qualifier;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@@ -52,6 +53,7 @@ import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.amqp.AmqpHeaders;
import org.springframework.integration.amqp.outbound.AmqpOutboundEndpoint;
+import org.springframework.integration.amqp.support.AmqpHeaderMapper;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.NullChannel;
import org.springframework.integration.context.NamedComponent;
@@ -86,6 +88,10 @@ public class AmqpOutboundChannelAdapterParserTests {
@Autowired
private ApplicationContext context;
+ @Autowired
+ @Qualifier("withCustomHeaderMapper.handler")
+ private MessageHandler amqpMessageHandlerWithCustomHeaderMapper;
+
@Test
public void verifyIdAsChannel() {
Object channel = context.getBean("rabbitOutbound");
@@ -289,6 +295,24 @@ public class AmqpOutboundChannelAdapterParserTests {
Mockito.anyBoolean(), Mockito.anyBoolean(), Mockito.any(BasicProperties.class), Mockito.any(byte[].class));
}
+ @Test
+ public void testInt2971HeaderMapperAndMappedHeadersExclusivity() {
+ try {
+ new ClassPathXmlApplicationContext("AmqpOutboundChannelAdapterParserTests-headerMapper-fail-context.xml", this.getClass());
+ }
+ catch (BeanDefinitionParsingException e) {
+ assertTrue(e.getMessage().startsWith("Configuration problem: The 'header-mapper' attribute " +
+ "is mutually exclusive with 'mapped-request-headers' or 'mapped-reply-headers'"));
+ }
+ }
+
+ @Test
+ public void testInt2971AmqpOutboundChannelAdapterWithCustomHeaderMapper() {
+ AmqpHeaderMapper headerMapper = TestUtils.getPropertyValue(this.amqpMessageHandlerWithCustomHeaderMapper, "headerMapper", AmqpHeaderMapper.class);
+ assertSame(this.context.getBean("customHeaderMapper"), headerMapper);
+ }
+
+
public static class FooAdvice extends AbstractRequestHandlerAdvice {
@Override
diff --git a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests-headerMapper-fail-context.xml b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests-headerMapper-fail-context.xml
new file mode 100644
index 0000000000..f845cf8297
--- /dev/null
+++ b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests-headerMapper-fail-context.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests.java b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests.java
index 1c0695d1a1..15da4042a5 100644
--- a/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests.java
+++ b/spring-integration-amqp/src/test/java/org/springframework/integration/amqp/config/AmqpOutboundGatewayParserTests.java
@@ -30,6 +30,7 @@ import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
@@ -264,6 +265,18 @@ public class AmqpOutboundGatewayParserTests {
}
+ @Test
+ public void testInt2971HeaderMapperAndMappedHeadersExclusivity() {
+ try {
+ new ClassPathXmlApplicationContext("AmqpOutboundGatewayParserTests-headerMapper-fail-context.xml", this.getClass());
+ }
+ catch (BeanDefinitionParsingException e) {
+ assertTrue(e.getMessage().startsWith("Configuration problem: The 'header-mapper' attribute " +
+ "is mutually exclusive with 'mapped-request-headers' or 'mapped-reply-headers'"));
+ }
+ }
+
+
public static class FooAdvice extends AbstractRequestHandlerAdvice {
@Override
diff --git a/src/reference/docbook/amqp.xml b/src/reference/docbook/amqp.xml
index d0339b2426..282d4ca7f4 100644
--- a/src/reference/docbook/amqp.xml
+++ b/src/reference/docbook/amqp.xml
@@ -27,7 +27,7 @@
(http://www.springsource.org/spring-amqp)
which "applies core Spring concepts to the development of AMQP-based
messaging solutions". Spring AMQP provides similar semantics as Spring JMS
- (http://.../spring-framework-reference.html#jms).
+ (http://static.springsource.org/spring/docs/current/spring-framework-reference/html/jms.html).
Whereas the provided AMQP Channel Adapters are intended for unidirectional
@@ -133,12 +133,12 @@
Optional (Defaults to true).
- HeaderMapper to use when receiving AMQP Messages.
+ AmqpHeaderMapper to use when receiving AMQP Messages.
Optional.
By default only standard AMQP properties (e.g. contentType) will be copied to and from
Spring Integration MessageHeaders. Any user-defined headers within the AMQP
MessageProperties will NOT be copied to or from an AMQP Message unless
- explicitly identified via 'requestHeaderNames' and/or 'replyHeaderNames' properties of this HeaderMapper.
+ explicitly identified via 'requestHeaderNames' and/or 'replyHeaderNames' properties of this DefaultAmqpHeaderMapper.
If you need to copy all user-defined headers simply use wild-card character '*'.
@@ -155,7 +155,7 @@ this list can also be simple patterns to be matched against the header names (e.
this list can also be simple patterns to be matched against the header names (e.g. "*" or "foo*, bar" or "*foo").
- Reference to the SimpleMessageListenerContainer
+ Reference to the SimpleMessageListenerContainer
to use for receiving AMQP Messages. If this attribute is provided,
then no other attribute related to the listener container
configuration should be provided. In other words, by
@@ -538,9 +538,9 @@ this list can also be simple patterns to be matched against the header names (e.
The Spring Integration AMPQ Adapters will map standard AMQP properties
automatically. These properties will be copied by default to and from
Spring Integration
- MessageHeaders
+ MessageHeaders
using the
- DefaultAmqpHeaderMapper.
+ DefaultAmqpHeaderMapper.
Of course, you can pass in your own implementation of AMQP specific header
@@ -552,7 +552,7 @@ this list can also be simple patterns to be matched against the header names (e.
will NOT be copied to or from an AMQP Message, unless explicitly specified
by the requestHeaderNames and/or
replyHeaderNames properties of the
- HeaderMapper.
+ DefaultAmqpHeaderMapper.
When mapping user-defined headers, the values can also contain simple