You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by nf...@apache.org on 2022/10/18 12:55:31 UTC

[camel] 02/02: CAMEL-16354: camel-core - Optimize Splitter using java.util.Scanner

This is an automated email from the ASF dual-hosted git repository.

nfilotto pushed a commit to branch CAMEL-16354/optimize-splitter
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 0ee5ae94fb13db71c9ff2e385da9e9eb80f17c9e
Author: Nicolas Filotto <nf...@talend.com>
AuthorDate: Tue Oct 18 14:55:04 2022 +0200

    CAMEL-16354: camel-core - Optimize Splitter using java.util.Scanner
---
 .../org/apache/camel/util/ObjectHelperTest.java    |  40 ++++++++-
 .../org/apache/camel/support/ObjectHelper.java     | 100 ++++++++++++++++++++-
 2 files changed, 136 insertions(+), 4 deletions(-)

diff --git a/core/camel-core/src/test/java/org/apache/camel/util/ObjectHelperTest.java b/core/camel-core/src/test/java/org/apache/camel/util/ObjectHelperTest.java
index 4527d95187a..49a36639ea0 100644
--- a/core/camel-core/src/test/java/org/apache/camel/util/ObjectHelperTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/util/ObjectHelperTest.java
@@ -29,6 +29,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Properties;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
 
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
@@ -47,8 +49,17 @@ import org.apache.camel.support.CamelContextHelper;
 import org.apache.camel.support.DefaultMessage;
 import org.apache.camel.support.ObjectHelper;
 import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 public class ObjectHelperTest {
 
@@ -1016,4 +1027,29 @@ public class ObjectHelperTest {
         assertEquals("foo", out2.get(0));
         assertEquals("bar", out2.get(1));
     }
+
+    @Test
+    void testIterableWithNullContent() {
+        assertEquals("", StreamSupport.stream(ObjectHelper.createIterable(null, ";;").spliterator(), false)
+                .collect(Collectors.joining("-")));
+    }
+
+    @Test
+    void testIterableWithEmptyContent() {
+        assertEquals("", StreamSupport.stream(ObjectHelper.createIterable("", ";;").spliterator(), false)
+                .collect(Collectors.joining("-")));
+    }
+
+    @Test
+    void testIterableWithOneElement() {
+        assertEquals("foo", StreamSupport.stream(ObjectHelper.createIterable("foo", ";;").spliterator(), false)
+                .collect(Collectors.joining("-")));
+    }
+
+    @ParameterizedTest
+    @ValueSource(strings = { "foo;;bar", ";;foo;;bar", "foo;;bar;;", ";;foo;;bar;;" })
+    void testIterableWithTwoElements(String content) {
+        assertEquals("foo-bar", StreamSupport.stream(ObjectHelper.createIterable(content, ";;").spliterator(), false)
+                .collect(Collectors.joining("-")));
+    }
 }
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 120b2af6a95..92accefbcd1 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
@@ -550,8 +550,10 @@ public final class ObjectHelper {
                     int count = StringHelper.countChar(value, DEFAULT_DELIMITER_CHAR) + 1;
                     return () -> StringHelper.splitOnCharacterAsIterator(value, DEFAULT_DELIMITER_CHAR, count);
                 }
+            } else if (pattern) {
+                return () -> new Scanner(value, delimiter);
             }
-            return () -> new Scanner(value, delimiter);
+            return () -> new StringIterator(value, delimiter);
         } else if (allowEmptyValues || org.apache.camel.util.ObjectHelper.isNotEmpty(value)) {
             return Collections.singletonList(value);
         } else {
@@ -770,9 +772,10 @@ public final class ObjectHelper {
                         return (Iterable<String>) () -> StringHelper.splitOnCharacterAsIterator(s, DEFAULT_DELIMITER_CHAR,
                                 count);
                     }
-                } else {
+                } else if (pattern) {
                     return (Iterable<String>) () -> new Scanner(s, delimiter);
                 }
+                return (Iterable<String>) () -> new StringIterator(s, delimiter);
             } else {
                 return (Iterable<Object>) () -> {
                     // use a plain iterator that returns the value as is as there are only a single value
@@ -886,4 +889,97 @@ public final class ObjectHelper {
         return false;
     }
 
+    /**
+     * An {@link Iterator} to split an input {@code String} content according to a specific separator.
+     */
+    private static class StringIterator implements Iterator<String> {
+
+        /**
+         * Flag indicating that the indexes have already been computed.
+         */
+        private boolean computed;
+        /**
+         * The current {@code from} index.
+         */
+        private int from;
+        /**
+         * The current {@code to} index.
+         */
+        private int to;
+        /**
+         * The content to split.
+         */
+        private final String content;
+        /**
+         * The separator to use when splitting the content.
+         */
+        private final String separator;
+        /**
+         * The length of the separator.
+         */
+        private final int separatorLength;
+        /**
+         * The length of the part of the content to split.
+         */
+        private final int contentLength;
+
+        /**
+         * Construct a {@code StringIterator} with the specified content and separator.
+         *
+         * @param content
+         * @param separator
+         */
+        StringIterator(String content, String separator) {
+            this.content = content;
+            this.separator = separator;
+            this.separatorLength = separator.length();
+            boolean skipStart = content.startsWith(separator);
+            boolean skipEnd = content.endsWith(separator);
+            if (skipStart && skipEnd) {
+                from = separatorLength;
+                contentLength = content.length() - separatorLength;
+            } else if (skipStart) {
+                from = separatorLength;
+                this.contentLength = content.length();
+            } else if (skipEnd) {
+                contentLength = content.length() - separatorLength;
+            } else {
+                this.contentLength = content.length();
+            }
+        }
+
+        @Override
+        public boolean hasNext() {
+            if (computed) {
+                return to != -1;
+            } else if (to == -1) {
+                return false;
+            }
+            int index = content.indexOf(separator, from);
+            if (index == -1 || index == contentLength) {
+                to = contentLength;
+            } else {
+                to = index;
+            }
+            computed = true;
+            return true;
+        }
+
+        @Override
+        public String next() {
+            if (!hasNext()) {
+                throw new NoSuchElementException();
+            }
+            String answer;
+            if (to == contentLength) {
+                answer = content.substring(from, contentLength);
+                to = -1;
+            } else {
+                answer = content.substring(from, to);
+                from = to + separatorLength;
+            }
+            computed = false;
+            return answer;
+        }
+    }
 }