This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/master by this push: new 3aa3cc4 CAMEL-14136: Fix ConcurrentModificationException in Scanner (#3313) 3aa3cc4 is described below commit 3aa3cc47247dee0e7e8a526cd55981dc1dd36db6 Author: Zohhak <chris...@gmx.de> AuthorDate: Wed Nov 6 08:21:57 2019 +0100 CAMEL-14136: Fix ConcurrentModificationException in Scanner (#3313) Internal use of non threadsafe map wrapped with synchronized block, extracted some static patterns into class static block --- .../org/apache/camel/support/ObjectHelper.java | 20 ++++++++--------- .../main/java/org/apache/camel/util/Scanner.java | 25 ++++++++++++++++------ 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/core/camel-support/src/main/java/org/apache/camel/support/ObjectHelper.java b/core/camel-support/src/main/java/org/apache/camel/support/ObjectHelper.java index fd51dcb..bae4ac5 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/ObjectHelper.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/ObjectHelper.java @@ -25,6 +25,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.concurrent.Callable; +import java.util.regex.Pattern; import java.util.stream.Stream; import org.w3c.dom.Node; @@ -42,7 +43,12 @@ import org.apache.camel.util.StringHelper; * A number of useful helper methods for working with Objects */ public final class ObjectHelper { + + static { + DEFAULT_PATTERN = Pattern.compile(",(?!(?:[^\\(,]|[^\\)],[^\\)])+\\))"); + } + private static final Pattern DEFAULT_PATTERN; private static final String DEFAULT_DELIMITER = ","; /** @@ -356,7 +362,6 @@ public final class ObjectHelper { if (value == null) { return Collections.emptyList(); } else if (delimiter != null && (pattern || value.contains(delimiter))) { - String del; if (DEFAULT_DELIMITER.equals(delimiter)) { // we use the default delimiter which is a comma, then cater for bean expressions with OGNL // which may have balanced parentheses pairs as well. @@ -368,11 +373,9 @@ public final class ObjectHelper { // -> bean=foo?method=killer(a,b) // -> bean=bar?method=great(a,b) // http://stackoverflow.com/questions/1516090/splitting-a-title-into-separate-parts - del = ",(?!(?:[^\\(,]|[^\\)],[^\\)])+\\))"; - } else { - del = delimiter; + return () -> new Scanner(value, DEFAULT_PATTERN); } - return () -> new Scanner(value, del); + return () -> new Scanner(value, delimiter); } else if (allowEmptyValues || org.apache.camel.util.ObjectHelper.isNotEmpty(value)) { return Collections.singletonList(value); } else { @@ -574,7 +577,6 @@ public final class ObjectHelper { // this code is optimized to only use a Scanner if needed, eg there is a delimiter if (delimiter != null && (pattern || s.contains(delimiter))) { - String del; if (DEFAULT_DELIMITER.equals(delimiter)) { // we use the default delimiter which is a comma, then cater for bean expressions with OGNL // which may have balanced parentheses pairs as well. @@ -586,11 +588,9 @@ public final class ObjectHelper { // -> bean=foo?method=killer(a,b) // -> bean=bar?method=great(a,b) // http://stackoverflow.com/questions/1516090/splitting-a-title-into-separate-parts - del = ",(?!(?:[^\\(,]|[^\\)],[^\\)])+\\))"; - } else { - del = delimiter; + return (Iterable<String>) () -> new Scanner(s, DEFAULT_PATTERN); } - return (Iterable<String>) () -> new Scanner(s, del); + return (Iterable<String>) () -> new Scanner(s, delimiter); } else { return (Iterable<Object>) () -> { // use a plain iterator that returns the value as is as there are only a single value diff --git a/core/camel-util/src/main/java/org/apache/camel/util/Scanner.java b/core/camel-util/src/main/java/org/apache/camel/util/Scanner.java index 74b2daf..f305498 100644 --- a/core/camel-util/src/main/java/org/apache/camel/util/Scanner.java +++ b/core/camel-util/src/main/java/org/apache/camel/util/Scanner.java @@ -44,6 +44,11 @@ import java.util.regex.Pattern; import static org.apache.camel.util.BufferCaster.cast; public final class Scanner implements Iterator<String>, Closeable { + + static { + WHITESPACE_PATTERN = Pattern.compile("\\s+"); + FIND_ANY_PATTERN = Pattern.compile("(?s).*"); + } private static final Map<String, Pattern> CACHE = new LinkedHashMap<String, Pattern>() { @Override @@ -51,10 +56,10 @@ public final class Scanner implements Iterator<String>, Closeable { return size() >= 7; } }; + + private static final Pattern WHITESPACE_PATTERN; - private static final String WHITESPACE_PATTERN = "\\s+"; - - private static final String FIND_ANY_PATTERN = "(?s).*"; + private static final Pattern FIND_ANY_PATTERN; private static final int BUFFER_SIZE = 1024; @@ -81,6 +86,10 @@ public final class Scanner implements Iterator<String>, Closeable { public Scanner(String source, String pattern) { this(new StringReader(Objects.requireNonNull(source, "source")), cachePattern(pattern)); } + + public Scanner(String source, Pattern pattern) { + this(new StringReader(Objects.requireNonNull(source, "source")), pattern); + } public Scanner(ReadableByteChannel source, String charsetName, String pattern) { this(Channels.newReader(Objects.requireNonNull(source, "source"), toDecoder(charsetName), -1), cachePattern(pattern)); @@ -92,7 +101,7 @@ public final class Scanner implements Iterator<String>, Closeable { private Scanner(Readable source, Pattern pattern) { this.source = source; - delimPattern = pattern != null ? pattern : cachePattern(WHITESPACE_PATTERN); + delimPattern = pattern != null ? pattern : WHITESPACE_PATTERN; buf = CharBuffer.allocate(BUFFER_SIZE); cast(buf).limit(0); matcher = delimPattern.matcher(buf); @@ -251,7 +260,7 @@ public final class Scanner implements Iterator<String>, Closeable { return null; } int tokenEnd = matcher.start(); - matcher.usePattern(cachePattern(FIND_ANY_PATTERN)); + matcher.usePattern(FIND_ANY_PATTERN); matcher.region(position, tokenEnd); if (matcher.matches()) { String s = matcher.group(); @@ -262,7 +271,7 @@ public final class Scanner implements Iterator<String>, Closeable { } } if (inputExhausted) { - matcher.usePattern(cachePattern(FIND_ANY_PATTERN)); + matcher.usePattern(FIND_ANY_PATTERN); matcher.region(position, buf.limit()); if (matcher.matches()) { String s = matcher.group(); @@ -302,7 +311,9 @@ public final class Scanner implements Iterator<String>, Closeable { if (pattern == null) { return null; } - return CACHE.computeIfAbsent(pattern, Pattern::compile); + synchronized (CACHE) { + return CACHE.computeIfAbsent(pattern, Pattern::compile); + } } }