You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2019/11/06 07:22:14 UTC
[camel] branch master updated: CAMEL-14136: Fix
ConcurrentModificationException in Scanner (#3313)
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 <ch...@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);
+ }
}
}