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.gitThe following commit(s) were added to refs/heads/master by this push:
new dd763f6 CAMEL-16462: camel-core - Optimize RecipientList EIP to reduce object allocations.
dd763f6 is described below
commit dd763f6b3bf48e0d71dea904961d16c089171ea2
Author: Claus Ibsen <
[hidden email]>
AuthorDate: Thu Apr 8 09:17:44 2021 +0200
CAMEL-16462: camel-core - Optimize RecipientList EIP to reduce object allocations.
---
.../org/apache/camel/support/ObjectHelper.java | 67 ++++++++++++++--------
.../java/org/apache/camel/util/StringHelper.java | 17 ++++++
.../org/apache/camel/util/StringHelperTest.java | 14 +++++
3 files changed, 73 insertions(+), 25 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 64f613f..c1b9767 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
@@ -38,6 +38,7 @@ import org.apache.camel.Ordered;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.TypeConverter;
import org.apache.camel.util.Scanner;
+import org.apache.camel.util.StringHelper;
/**
* A number of useful helper methods for working with Objects
@@ -45,11 +46,12 @@ import org.apache.camel.util.Scanner;
public final class ObjectHelper {
static {
- DEFAULT_PATTERN = Pattern.compile(",(?!(?:[^\\(,]|[^\\)],[^\\)])+\\))");
+ PARENTHESIS_PATTERN = Pattern.compile(",(?!(?:[^\\(,]|[^\\)],[^\\)])+\\))");
}
- private static final Pattern DEFAULT_PATTERN;
+ private static final Pattern PARENTHESIS_PATTERN;
private static final String DEFAULT_DELIMITER = ",";
+ private static final char DEFAULT_DELIMITER_CHAR = ',';
/**
* Utility classes should not have a public constructor.
@@ -522,18 +524,25 @@ public final class ObjectHelper {
if (value == null) {
return Collections.emptyList();
} else if (delimiter != null && (pattern || value.contains(delimiter))) {
+ // if its the default delimiter and the value has parenthesis
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.
- // if the value contains parentheses we need to balance those, to avoid iterating
- // in the middle of parentheses pair, so use this regular expression (a bit hard to read)
- // the regexp will split by comma, but honor parentheses pair that may include commas
- // as well, eg if value = "bean=foo?method=killer(a,b),bean=bar?method=great(a,b)"
- // then the regexp will split that into two:
- // -> bean=foo?method=killer(a,b)
- // -> bean=bar?method=great(a,b)
- //
http://stackoverflow.com/questions/1516090/splitting-a-title-into-separate-parts- return () -> new Scanner(value, DEFAULT_PATTERN);
+ if (value.indexOf('(') != -1 && value.indexOf(')') != -1) {
+ // we use the default delimiter which is a comma, then cater for bean expressions with OGNL
+ // which may have balanced parentheses pairs as well.
+ // if the value contains parentheses we need to balance those, to avoid iterating
+ // in the middle of parentheses pair, so use this regular expression (a bit hard to read)
+ // the regexp will split by comma, but honor parentheses pair that may include commas
+ // as well, eg if value = "bean=foo?method=killer(a,b),bean=bar?method=great(a,b)"
+ // then the regexp will split that into two:
+ // -> bean=foo?method=killer(a,b)
+ // -> bean=bar?method=great(a,b)
+ //
http://stackoverflow.com/questions/1516090/splitting-a-title-into-separate-parts+ return () -> new Scanner(value, PARENTHESIS_PATTERN);
+ } else {
+ // optimized split string on default delimiter
+ int count = StringHelper.countChar(value, DEFAULT_DELIMITER_CHAR) + 1;
+ return StringHelper.splitOnCharacterAsList(value, DEFAULT_DELIMITER_CHAR, count);
+ }
}
return () -> new Scanner(value, delimiter);
} else if (allowEmptyValues || org.apache.camel.util.ObjectHelper.isNotEmpty(value)) {
@@ -735,20 +744,28 @@ 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))) {
+ // if its the default delimiter and the value has parenthesis
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.
- // if the value contains parentheses we need to balance those, to avoid iterating
- // in the middle of parentheses pair, so use this regular expression (a bit hard to read)
- // the regexp will split by comma, but honor parentheses pair that may include commas
- // as well, eg if value = "bean=foo?method=killer(a,b),bean=bar?method=great(a,b)"
- // then the regexp will split that into two:
- // -> bean=foo?method=killer(a,b)
- // -> bean=bar?method=great(a,b)
- //
http://stackoverflow.com/questions/1516090/splitting-a-title-into-separate-parts- return (Iterable<String>) () -> new Scanner(s, DEFAULT_PATTERN);
+ if (s.indexOf('(') != -1 && s.indexOf(')') != -1) {
+ // we use the default delimiter which is a comma, then cater for bean expressions with OGNL
+ // which may have balanced parentheses pairs as well.
+ // if the value contains parentheses we need to balance those, to avoid iterating
+ // in the middle of parentheses pair, so use this regular expression (a bit hard to read)
+ // the regexp will split by comma, but honor parentheses pair that may include commas
+ // as well, eg if value = "bean=foo?method=killer(a,b),bean=bar?method=great(a,b)"
+ // then the regexp will split that into two:
+ // -> bean=foo?method=killer(a,b)
+ // -> bean=bar?method=great(a,b)
+ //
http://stackoverflow.com/questions/1516090/splitting-a-title-into-separate-parts+ return (Iterable<String>) () -> new Scanner(s, PARENTHESIS_PATTERN);
+ } else {
+ // optimized split string on default delimiter
+ int count = StringHelper.countChar(s, DEFAULT_DELIMITER_CHAR) + 1;
+ return StringHelper.splitOnCharacterAsList(s, DEFAULT_DELIMITER_CHAR, count);
+ }
+ } else {
+ return (Iterable<String>) () -> new Scanner(s, delimiter);
}
- 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/StringHelper.java b/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java
index ddde325..1f35195 100644
--- a/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java
+++ b/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java
@@ -396,6 +396,23 @@ public final class StringHelper {
return rc;
}
+ public static List<String> splitOnCharacterAsList(String value, char needle, int count) {
+ List<String> rc = new ArrayList<>(count);
+ int pos = 0;
+ for (int i = 0; i < count; i++) {
+ int end = value.indexOf(needle, pos);
+ if (end != -1) {
+ String part = value.substring(pos, end);
+ pos = end + 1;
+ rc.add(part);
+ } else {
+ rc.add(value.substring(pos));
+ break;
+ }
+ }
+ return rc;
+ }
+
/**
* Removes any starting characters on the given text which match the given character
*
diff --git a/core/camel-util/src/test/java/org/apache/camel/util/StringHelperTest.java b/core/camel-util/src/test/java/org/apache/camel/util/StringHelperTest.java
index 3c89c24..c4e6dc0 100644
--- a/core/camel-util/src/test/java/org/apache/camel/util/StringHelperTest.java
+++ b/core/camel-util/src/test/java/org/apache/camel/util/StringHelperTest.java
@@ -16,6 +16,8 @@
*/
package org.apache.camel.util;
+import java.util.List;
+
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -120,4 +122,16 @@ public class StringHelperTest {
assertEquals("jms:queue:bar?blah=123", replaceFirst("jms:queue:foo?blah=123", "foo", "bar"));
assertEquals("jms:queue:bar?blah=foo", replaceFirst("jms:queue:foo?blah=foo", "foo", "bar"));
}
+
+ @Test
+ public void testSplitOnCharacterAsList() throws Exception {
+ List<String> list = splitOnCharacterAsList("foo", ',', 1);
+ assertEquals(1, list.size());
+ assertEquals("foo", list.get(0));
+
+ list = splitOnCharacterAsList("foo,bar", ',', 2);
+ assertEquals(2, list.size());
+ assertEquals("foo", list.get(0));
+ assertEquals("bar", list.get(1));
+ }
}