From 51d9c8e42ccde1a1a27e6a479a50d24187963a40 Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Fri, 22 Feb 2008 19:34:08 +0000 Subject: [PATCH] Added header-copying constructor to GenericMessage (INT-123). Also simplified the AbstractMessageHandlerAdapter. --- .../AbstractMessageHandlerAdapter.java | 40 ++++++------------- .../handler/DefaultMessageHandlerAdapter.java | 21 +++++----- .../config/DefaultMessageHandlerCreator.java | 3 +- .../integration/message/GenericMessage.java | 20 +++++++++- .../integration/message/MessageHeader.java | 16 +++++--- .../router/RouterMessageHandlerAdapter.java | 3 -- .../DefaultMessageHandlerAdapterTests.java | 8 ++-- .../message/GenericMessageTests.java | 11 +++++ .../message/MessageHeaderTests.java | 40 +++++++++++++++++-- 9 files changed, 104 insertions(+), 58 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageHandlerAdapter.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageHandlerAdapter.java index 33475b8b44..55693b2292 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageHandlerAdapter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/AbstractMessageHandlerAdapter.java @@ -21,9 +21,10 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.Ordered; +import org.springframework.integration.message.GenericMessage; import org.springframework.integration.message.Message; +import org.springframework.integration.message.MessageHeader; import org.springframework.integration.message.MessageMapper; -import org.springframework.integration.message.SimplePayloadMessageMapper; import org.springframework.integration.util.SimpleMethodInvoker; import org.springframework.util.Assert; @@ -45,8 +46,6 @@ public abstract class AbstractMessageHandlerAdapter implements MessageHandler private volatile String methodName; - private volatile MessageMapper mapper = new SimplePayloadMessageMapper(); - private volatile SimpleMethodInvoker invoker; private volatile int order = Integer.MAX_VALUE; @@ -61,28 +60,11 @@ public abstract class AbstractMessageHandlerAdapter implements MessageHandler this.object = object; } - protected Object getObject() { - return this.object; - } - public void setMethodName(String methodName) { Assert.notNull(methodName, "'methodName' must not be null"); this.methodName = methodName; } - public String getMethodName() { - return this.methodName; - } - - public void setMapper(MessageMapper mapper) { - Assert.notNull(mapper, "'mapper' must not be null"); - this.mapper = mapper; - } - - protected MessageMapper getMapper() { - return this.mapper; - } - public void setOrder(int order) { this.order = order; } @@ -94,22 +76,22 @@ public abstract class AbstractMessageHandlerAdapter implements MessageHandler public final void afterPropertiesSet() { this.validate(); synchronized (this.lifecycleMonitor) { + if (this.initialized) { + return; + } this.invoker = new SimpleMethodInvoker(this.object, this.methodName); this.initialized = true; } } - public final boolean isInitialized() { - synchronized (this.lifecycleMonitor) { - return this.initialized; - } - } - public final Message handle(Message message) { + if (!this.initialized) { + this.afterPropertiesSet(); + } Object result = this.doHandle(message, invoker); if (result != null) { Message reply = (result instanceof Message) ? (Message) result : - this.mapper.toMessage(result); + this.createReplyMessage(result, message.getHeader()); Object correlationId = reply.getHeader().getCorrelationId(); if (correlationId == null) { Object orginalCorrelationId = message.getHeader().getCorrelationId(); @@ -127,6 +109,10 @@ public abstract class AbstractMessageHandlerAdapter implements MessageHandler protected void validate() { } + protected Message createReplyMessage(Object payload, MessageHeader originalMessageHeader) { + return new GenericMessage(payload, originalMessageHeader); + } + /** * Subclasses must implement this method. The invoker has been created for * the provided target object and method. May return an object of type diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/DefaultMessageHandlerAdapter.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/DefaultMessageHandlerAdapter.java index 276534a842..b8cdbc24a2 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/DefaultMessageHandlerAdapter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/DefaultMessageHandlerAdapter.java @@ -33,24 +33,23 @@ import org.springframework.integration.util.SimpleMethodInvoker; */ public class DefaultMessageHandlerAdapter extends AbstractMessageHandlerAdapter implements Ordered { - private boolean shouldUseMapperOnInvocation = true; - + private boolean expectsMessage = false; /** - * Specify whether the handler method should use the - * {@link org.springframework.integration.message.MessageMapper} when - * invoking the target method. Default is true. To force - * passing the {@link Message} directly, set this to false. + * Specify whether the handler should pass the message when invoking the + * target method. The default is false indicating that the + * message's payload should be passed as the argument. To force + * passing the {@link Message} directly, set this to true. */ - public void setShouldUseMapperOnInvocation(boolean shouldUseMapperOnInvocation) { - this.shouldUseMapperOnInvocation = shouldUseMapperOnInvocation; + public void setExpectsMessage(boolean expectsMessage) { + this.expectsMessage = expectsMessage; } public Object doHandle(Message message, SimpleMethodInvoker invoker) { - if (this.shouldUseMapperOnInvocation) { - return invoker.invokeMethod(this.getMapper().fromMessage(message)); + if (this.expectsMessage) { + return invoker.invokeMethod(message); } - return invoker.invokeMethod(message); + return invoker.invokeMethod(message.getPayload()); } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/config/DefaultMessageHandlerCreator.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/config/DefaultMessageHandlerCreator.java index 4a05bbf46d..4186618604 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/config/DefaultMessageHandlerCreator.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/config/DefaultMessageHandlerCreator.java @@ -41,8 +41,7 @@ public class DefaultMessageHandlerCreator extends AbstractMessageHandlerCreator throw new MessagingConfigurationException("exactly one method parameter is required"); } DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter(); - boolean expectsMessage = (Message.class.isAssignableFrom(types[0])); - adapter.setShouldUseMapperOnInvocation(!expectsMessage); + adapter.setExpectsMessage(Message.class.isAssignableFrom(types[0])); return adapter; } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/message/GenericMessage.java b/spring-integration-core/src/main/java/org/springframework/integration/message/GenericMessage.java index 8e2b1897b1..aeb7825095 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/message/GenericMessage.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/message/GenericMessage.java @@ -17,9 +17,10 @@ package org.springframework.integration.message; import java.util.Date; +import java.util.Set; -import org.springframework.integration.util.RandomUuidGenerator; import org.springframework.integration.util.IdGenerator; +import org.springframework.integration.util.RandomUuidGenerator; import org.springframework.util.Assert; /** @@ -63,6 +64,11 @@ public class GenericMessage implements Message { this.payload = payload; } + public GenericMessage(T payload, MessageHeader headerToCopy) { + this(payload); + this.copyHeader(headerToCopy); + } + public Object getId() { return this.id; @@ -85,4 +91,16 @@ public class GenericMessage implements Message { return "[ID=" + this.id + "][Header=" + this.header + "][Payload='" + this.payload + "']"; } + private void copyHeader(final MessageHeader headerToCopy) { + Set propertyNames = headerToCopy.getPropertyNames(); + for (String key : propertyNames) { + this.header.setProperty(key, headerToCopy.getProperty(key)); + } + Set attributeNames = headerToCopy.getAttributeNames(); + for (String key : attributeNames) { + this.header.setAttribute(key, headerToCopy.getAttribute(key)); + } + this.header.setReturnAddress(headerToCopy.getReturnAddress()); + } + } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/message/MessageHeader.java b/spring-integration-core/src/main/java/org/springframework/integration/message/MessageHeader.java index 05815dd68f..6843575e42 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/message/MessageHeader.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/message/MessageHeader.java @@ -18,10 +18,10 @@ package org.springframework.integration.message; import java.util.Date; import java.util.HashSet; -import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; /** * A holder for Message metadata. This includes information that may be used by @@ -48,7 +48,7 @@ public class MessageHeader { private final Properties properties = new Properties(); - private final Map attributes = new ConcurrentHashMap(); + private final ConcurrentMap attributes = new ConcurrentHashMap(); /** @@ -110,8 +110,8 @@ public class MessageHeader { return this.properties.getProperty(key); } - public void setProperty(String key, String value) { - this.properties.setProperty(key, value); + public String setProperty(String key, String value) { + return (String) this.properties.setProperty(key, value); } public Set getPropertyNames() { @@ -126,8 +126,12 @@ public class MessageHeader { return this.attributes.get(key); } - public void setAttribute(String key, Object value) { - this.attributes.put(key, value); + public Object setAttribute(String key, Object value) { + return this.attributes.put(key, value); + } + + public Object setAttributeIfAbsent(String key, Object value) { + return this.attributes.putIfAbsent(key, value); } public Set getAttributeNames() { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/router/RouterMessageHandlerAdapter.java b/spring-integration-core/src/main/java/org/springframework/integration/router/RouterMessageHandlerAdapter.java index 5ecd3964b0..49accd0325 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/router/RouterMessageHandlerAdapter.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/router/RouterMessageHandlerAdapter.java @@ -67,9 +67,6 @@ public class RouterMessageHandlerAdapter extends AbstractMessageHandlerAdapter i @Override protected Object doHandle(Message message, SimpleMethodInvoker invoker) { - if (!this.isInitialized()) { - this.afterPropertiesSet(); - } if (method.getParameterTypes().length != 1) { throw new MessagingConfigurationException( "method must accept exactly one parameter"); diff --git a/spring-integration-core/src/test/java/org/springframework/integration/handler/DefaultMessageHandlerAdapterTests.java b/spring-integration-core/src/test/java/org/springframework/integration/handler/DefaultMessageHandlerAdapterTests.java index de63d1cd39..2c2b79cddc 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/handler/DefaultMessageHandlerAdapterTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/handler/DefaultMessageHandlerAdapterTests.java @@ -51,7 +51,7 @@ public class DefaultMessageHandlerAdapterTests { @Test public void testMessageAsMethodParameterAndObjectAsReturnValue() { DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter(); - adapter.setShouldUseMapperOnInvocation(false); + adapter.setExpectsMessage(true); adapter.setObject(new TestHandler()); adapter.setMethodName("acceptMessageAndReturnObject"); adapter.afterPropertiesSet(); @@ -62,7 +62,7 @@ public class DefaultMessageHandlerAdapterTests { @Test public void testMessageAsMethodParameterAndMessageAsReturnValue() { DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter(); - adapter.setShouldUseMapperOnInvocation(false); + adapter.setExpectsMessage(true); adapter.setObject(new TestHandler()); adapter.setMethodName("acceptMessageAndReturnMessage"); adapter.afterPropertiesSet(); @@ -73,7 +73,7 @@ public class DefaultMessageHandlerAdapterTests { @Test public void testMessageSubclassAsMethodParameterAndMessageAsReturnValue() { DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter(); - adapter.setShouldUseMapperOnInvocation(false); + adapter.setExpectsMessage(true); adapter.setObject(new TestHandler()); adapter.setMethodName("acceptMessageSubclassAndReturnMessage"); adapter.afterPropertiesSet(); @@ -84,7 +84,7 @@ public class DefaultMessageHandlerAdapterTests { @Test public void testMessageSubclassAsMethodParameterAndMessageSubclassAsReturnValue() { DefaultMessageHandlerAdapter adapter = new DefaultMessageHandlerAdapter(); - adapter.setShouldUseMapperOnInvocation(false); + adapter.setExpectsMessage(true); adapter.setObject(new TestHandler()); adapter.setMethodName("acceptMessageSubclassAndReturnMessageSubclass"); adapter.afterPropertiesSet(); diff --git a/spring-integration-core/src/test/java/org/springframework/integration/message/GenericMessageTests.java b/spring-integration-core/src/test/java/org/springframework/integration/message/GenericMessageTests.java index cb44669a8e..3fdf7082ae 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/message/GenericMessageTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/message/GenericMessageTests.java @@ -16,6 +16,7 @@ package org.springframework.integration.message; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -55,4 +56,14 @@ public class GenericMessageTests { assertFalse(message.isExpired()); } + @Test + public void testMessageHeaderCopied() { + MessageHeader header = new MessageHeader(); + header.setAttribute("testAttribute", new Integer(123)); + header.setProperty("testProperty", "foo"); + GenericMessage message = new GenericMessage("test", header); + assertEquals(new Integer(123), message.getHeader().getAttribute("testAttribute")); + assertEquals("foo", message.getHeader().getProperty("testProperty")); + } + } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/message/MessageHeaderTests.java b/spring-integration-core/src/test/java/org/springframework/integration/message/MessageHeaderTests.java index f37d8ac703..91e40d885f 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/message/MessageHeaderTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/message/MessageHeaderTests.java @@ -17,6 +17,7 @@ package org.springframework.integration.message; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -39,24 +40,55 @@ public class MessageHeaderTests { @Test public void testAttributes() { MessageHeader header = new MessageHeader(); - Integer integer = new Integer(123); - header.setAttribute("test", integer); - assertEquals(integer, header.getAttribute("test")); + Integer value = new Integer(123); + Object previousValue = header.setAttribute("test", value); + assertNull(previousValue); + assertEquals(value, header.getAttribute("test")); assertNull(header.getAttribute("nosuchattribute")); Set names = header.getAttributeNames(); assertEquals(1, names.size()); assertTrue(names.contains("test")); + Integer newValue = new Integer(456); + previousValue = header.setAttribute("test", newValue); + assertEquals(value, previousValue); + assertEquals(newValue, header.getAttribute("test")); } @Test public void testProperties() { MessageHeader header = new MessageHeader(); - header.setProperty("foo", "bar"); + String previousValue = header.setProperty("foo", "bar"); + assertNull(previousValue); assertEquals("bar", header.getProperty("foo")); assertNull(header.getProperty("nosuchproperty")); Set names = header.getPropertyNames(); assertEquals(1, names.size()); assertTrue(names.contains("foo")); + previousValue = header.setProperty("foo", "baz"); + assertEquals("bar", previousValue); + assertEquals("baz", header.getProperty("foo")); + } + + @Test + public void testSetAttributeIfAbsent() { + MessageHeader header = new MessageHeader(); + Integer integer = new Integer(123); + assertNull(header.getAttribute("test")); + assertFalse(header.getAttributeNames().contains("test")); + Object existingValue = header.setAttributeIfAbsent("test", integer); + assertNull(existingValue); + assertEquals(integer, header.getAttribute("test")); + assertTrue(header.getAttributeNames().contains("test")); + } + + @Test + public void testSetAttributeIfAbsentDoesNotOverride() { + MessageHeader header = new MessageHeader(); + Integer originalValue = new Integer(123); + header.setAttributeIfAbsent("test", originalValue); + Object existingValue = header.setAttributeIfAbsent("test", new Integer(456)); + assertEquals(originalValue, header.getAttribute("test")); + assertEquals(originalValue, existingValue); } }