Repository: camel Updated Branches: refs/heads/master 345203a12 -> 6e18ca3ee
CAMEL-8415: DefaultExchangeHolder - Only transfer primitive headers/properties Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/6e18ca3e Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/6e18ca3e Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/6e18ca3e Branch: refs/heads/master Commit: 6e18ca3ee11aeb4fb43fe8f50954592bfb567ca7 Parents: 345203a Author: Claus Ibsen <[email protected]> Authored: Tue Sep 8 10:07:31 2015 +0200 Committer: Claus Ibsen <[email protected]> Committed: Tue Sep 8 10:07:31 2015 +0200 ---------------------------------------------------------------------- .../camel/impl/DefaultExchangeHolder.java | 68 ++++++++++++++++++-- .../camel/impl/DefaultExchangeHolderTest.java | 25 +++++++ ...eadLetterQueueUsingTransferExchangeTest.java | 15 +---- 3 files changed, 91 insertions(+), 17 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/6e18ca3e/camel-core/src/main/java/org/apache/camel/impl/DefaultExchangeHolder.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultExchangeHolder.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultExchangeHolder.java index 0605649..ea9713c 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/DefaultExchangeHolder.java +++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultExchangeHolder.java @@ -52,7 +52,7 @@ import org.slf4j.LoggerFactory; * <li>exception</li> * </ul> * The body is serialized and stored as serialized bytes. The header and exchange properties only include - * primitive, and String types. Any other type is skipped. + * primitive, and String types (and Exception types for exchange properties). Any other type is skipped. * <p/> * Any object that is not serializable will be skipped and Camel will log this at WARN level. * @@ -184,7 +184,7 @@ public class DefaultExchangeHolder implements Serializable { private Map<String, Object> safeSetInHeaders(Exchange exchange) { if (exchange.getIn().hasHeaders()) { - Map<String, Object> map = checkValidMapObjects("in headers", exchange, exchange.getIn().getHeaders()); + Map<String, Object> map = checkValidHeaderObjects("in headers", exchange, exchange.getIn().getHeaders()); if (map != null && !map.isEmpty()) { inHeaders = new LinkedHashMap<String, Object>(map); } @@ -194,7 +194,7 @@ public class DefaultExchangeHolder implements Serializable { private Map<String, Object> safeSetOutHeaders(Exchange exchange) { if (exchange.hasOut() && exchange.getOut().hasHeaders()) { - Map<String, Object> map = checkValidMapObjects("out headers", exchange, exchange.getOut().getHeaders()); + Map<String, Object> map = checkValidHeaderObjects("out headers", exchange, exchange.getOut().getHeaders()); if (map != null && !map.isEmpty()) { outHeaders = new LinkedHashMap<String, Object>(map); } @@ -204,7 +204,7 @@ public class DefaultExchangeHolder implements Serializable { private Map<String, Object> safeSetProperties(Exchange exchange) { if (exchange.hasProperties()) { - Map<String, Object> map = checkValidMapObjects("properties", exchange, exchange.getProperties()); + Map<String, Object> map = checkValidExchangePropertyObjects("properties", exchange, exchange.getProperties()); if (map != null && !map.isEmpty()) { properties = new LinkedHashMap<String, Object>(map); } @@ -226,7 +226,7 @@ public class DefaultExchangeHolder implements Serializable { } } - private static Map<String, Object> checkValidMapObjects(String type, Exchange exchange, Map<String, Object> map) { + private static Map<String, Object> checkValidHeaderObjects(String type, Exchange exchange, Map<String, Object> map) { if (map == null) { return null; } @@ -251,6 +251,31 @@ public class DefaultExchangeHolder implements Serializable { return result; } + private static Map<String, Object> checkValidExchangePropertyObjects(String type, Exchange exchange, Map<String, Object> map) { + if (map == null) { + return null; + } + + Map<String, Object> result = new LinkedHashMap<String, Object>(); + for (Map.Entry<String, Object> entry : map.entrySet()) { + + // silently skip any values which is null + Object value = getValidExchangePropertyValue(entry.getKey(), entry.getValue()); + if (value != null) { + Serializable converted = exchange.getContext().getTypeConverter().convertTo(Serializable.class, exchange, value); + if (converted != null) { + result.put(entry.getKey(), converted); + } else { + logCannotSerializeObject(type, entry.getKey(), entry.getValue()); + } + } else { + logInvalidExchangePropertyValue(type, entry.getKey(), entry.getValue()); + } + } + + return result; + } + /** * We only want to store header values of primitive and String related types. * <p/> @@ -288,6 +313,25 @@ public class DefaultExchangeHolder implements Serializable { return null; } + /** + * We only want to store exchange property values of primitive and String related types, and + * as well any caught exception that Camel routing engine has caught. + * <p/> + * This default implementation will allow the same values as {@link #getValidHeaderValue(String, Object)} + * and in addition any value of type {@link Throwable}. + * + * @param propertyName the property name + * @param propertyValue the property value + * @return the value to use, <tt>null</tt> to ignore this header + */ + protected static Object getValidExchangePropertyValue(String propertyName, Object propertyValue) { + // for exchange properties we also allow exception to be transferred so people can store caught exception + if (propertyValue instanceof Throwable) { + return propertyValue; + } + return getValidHeaderValue(propertyName, propertyValue); + } + private static void logCannotSerializeObject(String type, String key, Object value) { if (key.startsWith("Camel")) { // log Camel at DEBUG level @@ -316,4 +360,18 @@ public class DefaultExchangeHolder implements Serializable { } } + private static void logInvalidExchangePropertyValue(String type, String key, Object value) { + if (key.startsWith("Camel")) { + // log Camel at DEBUG level + if (LOG.isDebugEnabled()) { + LOG.debug("Exchange {} containing key: {} with object: {} of type: {} is not valid exchange property type, it will be excluded by the holder." + , new Object[]{type, key, value, ObjectHelper.classCanonicalName(value)}); + } + } else { + // log regular at WARN level + LOG.warn("Exchange {} containing key: {} with object: {} of type: {} is not valid exchange property type, it will be excluded by the holder." + , new Object[]{type, key, value, ObjectHelper.classCanonicalName(value)}); + } + } + } http://git-wip-us.apache.org/repos/asf/camel/blob/6e18ca3e/camel-core/src/test/java/org/apache/camel/impl/DefaultExchangeHolderTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/impl/DefaultExchangeHolderTest.java b/camel-core/src/test/java/org/apache/camel/impl/DefaultExchangeHolderTest.java index f5150b8..cdb6ddc 100644 --- a/camel-core/src/test/java/org/apache/camel/impl/DefaultExchangeHolderTest.java +++ b/camel-core/src/test/java/org/apache/camel/impl/DefaultExchangeHolderTest.java @@ -127,6 +127,31 @@ public class DefaultExchangeHolderTest extends ContextTestSupport { assertNull(exchange.getIn().getHeader("Foo")); } + public void testCaughtException() throws Exception { + // use a mixed list, the MyFoo is not serializable so the entire list should be skipped + List<Object> list = new ArrayList<Object>(); + list.add("I am okay"); + list.add(new MyFoo("Tiger")); + + Exchange exchange = new DefaultExchange(context); + exchange.getIn().setBody("Hello World"); + exchange.getIn().setHeader("Foo", list); + exchange.getIn().setHeader("Bar", 123); + exchange.setProperty(Exchange.EXCEPTION_CAUGHT, new IllegalArgumentException("Forced")); + + DefaultExchangeHolder holder = DefaultExchangeHolder.marshal(exchange); + + exchange = new DefaultExchange(context); + DefaultExchangeHolder.unmarshal(exchange, holder); + + // the caught exception should be included + assertEquals("Hello World", exchange.getIn().getBody()); + assertEquals(123, exchange.getIn().getHeader("Bar")); + assertNull(exchange.getIn().getHeader("Foo")); + assertNotNull(exchange.getProperty(Exchange.EXCEPTION_CAUGHT)); + assertEquals("Forced", exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class).getMessage()); + } + public void testFileNotSupported() throws Exception { Exchange exchange = new DefaultExchange(context); exchange.getIn().setBody(new File("src/test/resources/log4j.properties")); http://git-wip-us.apache.org/repos/asf/camel/blob/6e18ca3e/components/camel-jms/src/test/java/org/apache/camel/component/jms/JmsDeadLetterQueueUsingTransferExchangeTest.java ---------------------------------------------------------------------- diff --git a/components/camel-jms/src/test/java/org/apache/camel/component/jms/JmsDeadLetterQueueUsingTransferExchangeTest.java b/components/camel-jms/src/test/java/org/apache/camel/component/jms/JmsDeadLetterQueueUsingTransferExchangeTest.java index fff728b..2128eed 100644 --- a/components/camel-jms/src/test/java/org/apache/camel/component/jms/JmsDeadLetterQueueUsingTransferExchangeTest.java +++ b/components/camel-jms/src/test/java/org/apache/camel/component/jms/JmsDeadLetterQueueUsingTransferExchangeTest.java @@ -58,9 +58,8 @@ public class JmsDeadLetterQueueUsingTransferExchangeTest extends CamelTestSuppor assertMockEndpointsSatisfied(); Exchange dead = mock.getReceivedExchanges().get(0); - // caused exception details is stored as headers - assertEquals("Kabom", dead.getIn().getHeader("CausedExceptionMessage", String.class)); - assertEquals("java.lang.IllegalArgumentException", dead.getIn().getHeader("CausedExceptionType", String.class)); + // caused exception is stored as a property + assertEquals("Kabom", dead.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class).getMessage()); } protected CamelContext createCamelContext() throws Exception { @@ -77,15 +76,7 @@ public class JmsDeadLetterQueueUsingTransferExchangeTest extends CamelTestSuppor return new RouteBuilder() { @Override public void configure() throws Exception { - errorHandler(deadLetterChannel(getUri()).onPrepareFailure(new Processor() { - @Override - public void process(Exchange exchange) throws Exception { - // store exception as a string - Exception cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class); - exchange.getIn().setHeader("CausedExceptionMessage", cause.getMessage()); - exchange.getIn().setHeader("CausedExceptionType", cause.getClass().getName()); - } - }).disableRedelivery()); + errorHandler(deadLetterChannel(getUri()).disableRedelivery()); from("direct:start").process(new Processor() { public void process(Exchange exchange) throws Exception {
