CAMEL-8829: Do a defensive copy of the message when creating correlated copy, to eavoid any ConcurrentModificationException such as routing to logs using concurrent threads or if using wire tap EIP etc.
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/6d6d1b73 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/6d6d1b73 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/6d6d1b73 Branch: refs/heads/master Commit: 6d6d1b736e25b139671ba9a652b6b7ac9e524a3b Parents: d13afd1 Author: Claus Ibsen <davscl...@apache.org> Authored: Thu Jun 4 10:16:39 2015 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Thu Jun 4 10:16:39 2015 +0200 ---------------------------------------------------------------------- .../org/apache/camel/impl/DefaultExchange.java | 21 ++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/6d6d1b73/camel-core/src/main/java/org/apache/camel/impl/DefaultExchange.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultExchange.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultExchange.java index d24eed6..6704cdf 100644 --- a/camel-core/src/main/java/org/apache/camel/impl/DefaultExchange.java +++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultExchange.java @@ -29,6 +29,7 @@ import org.apache.camel.Message; import org.apache.camel.MessageHistory; import org.apache.camel.spi.Synchronization; import org.apache.camel.spi.UnitOfWork; +import org.apache.camel.util.CaseInsensitiveMap; import org.apache.camel.util.EndpointHelper; import org.apache.camel.util.ExchangeHelper; import org.apache.camel.util.ObjectHelper; @@ -91,18 +92,18 @@ public final class DefaultExchange implements Exchange { DefaultExchange exchange = new DefaultExchange(this); if (hasProperties()) { - exchange.setProperties(safeCopy(getProperties())); + exchange.setProperties(safeCopyProperties(getProperties())); } if (safeCopy) { exchange.getIn().setBody(getIn().getBody()); if (getIn().hasHeaders()) { - exchange.getIn().setHeaders(safeCopy(getIn().getHeaders())); + exchange.getIn().setHeaders(safeCopyHeaders(getIn().getHeaders())); } if (hasOut()) { exchange.getOut().setBody(getOut().getBody()); if (getOut().hasHeaders()) { - exchange.getOut().setHeaders(safeCopy(getOut().getHeaders())); + exchange.getOut().setHeaders(safeCopyHeaders(getOut().getHeaders())); } } } else { @@ -118,11 +119,23 @@ public final class DefaultExchange implements Exchange { } @SuppressWarnings("unchecked") - private static Map<String, Object> safeCopy(Map<String, Object> properties) { + private static Map<String, Object> safeCopyHeaders(Map<String, Object> headers) { + if (headers == null) { + return null; + } + + Map<String, Object> answer = new CaseInsensitiveMap(); + answer.putAll(headers); + return answer; + } + + @SuppressWarnings("unchecked") + private static Map<String, Object> safeCopyProperties(Map<String, Object> properties) { if (properties == null) { return null; } + // TODO: properties should use same map kind as headers Map<String, Object> answer = new ConcurrentHashMap<String, Object>(properties); // safe copy message history using a defensive copy