diff --git a/donkey/src/main/java/com/mirth/connect/donkey/model/message/Message.java b/donkey/src/main/java/com/mirth/connect/donkey/model/message/Message.java index ffac777dbb..c56dca75a6 100644 --- a/donkey/src/main/java/com/mirth/connect/donkey/model/message/Message.java +++ b/donkey/src/main/java/com/mirth/connect/donkey/model/message/Message.java @@ -14,12 +14,14 @@ import java.util.Calendar; import java.util.Collections; import java.util.Comparator; +import java.util.ConcurrentModificationException; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import com.mirth.connect.donkey.model.message.attachment.Attachment; +import com.mirth.connect.donkey.util.MapUtil; import com.thoughtworks.xstream.annotations.XStreamAlias; @XStreamAlias("message") @@ -152,8 +154,8 @@ public int compare(ConnectorMessage m1, ConnectorMessage m2) { if (sourceMap == null) { sourceMap = connectorMessage.getSourceMap(); } - responseMap.putAll(connectorMessage.getResponseMap()); - channelMap.putAll(connectorMessage.getChannelMap()); + MapUtil.safePutAll(responseMap, connectorMessage.getResponseMap(), 5); + MapUtil.safePutAll(channelMap, connectorMessage.getChannelMap(), 5); } } diff --git a/donkey/src/main/java/com/mirth/connect/donkey/util/MapUtil.java b/donkey/src/main/java/com/mirth/connect/donkey/util/MapUtil.java index d13a3485c3..363176603d 100644 --- a/donkey/src/main/java/com/mirth/connect/donkey/util/MapUtil.java +++ b/donkey/src/main/java/com/mirth/connect/donkey/util/MapUtil.java @@ -9,6 +9,7 @@ package com.mirth.connect.donkey.util; +import java.util.ConcurrentModificationException; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; @@ -132,4 +133,37 @@ public static Map deserializeMapWithInvalidValues(Serializer ser return map; } + + /** + * Tries to safely put all entries from a possibly concurrently modified source map into the + * target map. Retries up to the specified maxAttempts if ConcurrentModificationException is + * thrown, sleeping 10ms between retries. + * + * @param target + * The destination map + * @param source + * The source map that might be modified concurrently + * @param maxAttempts + * The maximum number of retries + * @return true if the putAll succeeded, false if it failed after retries + */ + public static boolean safePutAll(Map target, Map source, final int maxAttempts) { + + int attempts = 0; + while (attempts++ < maxAttempts) { + try { + target.putAll(source); + return true; + } catch (ConcurrentModificationException e) { + try { + Thread.sleep(10); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + return false; + } + } + } + + return false; + } }