You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by or...@apache.org on 2023/10/27 15:17:25 UTC

(camel) branch main updated (e1da6dd4f8f -> 9b59f350f6b)

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

orpiske pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


    from e1da6dd4f8f Update known camel releases
     new a32f36497a7 (chores) camel-platform-http-vertx: break large methods
     new 9b59f350f6b (chores) camel-core: break large methods

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../http/vertx/VertxPlatformHttpConsumer.java      |  77 +++++---
 .../http/vertx/VertxPlatformHttpSupport.java       | 220 ++++++++++++---------
 .../camel/support/DefaultHeaderFilterStrategy.java |  77 +++++---
 .../org/apache/camel/support/ObjectHelper.java     | 216 +++++++++++---------
 4 files changed, 343 insertions(+), 247 deletions(-)


(camel) 01/02: (chores) camel-platform-http-vertx: break large methods

Posted by or...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

orpiske pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git

commit a32f36497a7f5522575a5bb94fa255ee58fc9633
Author: Otavio Rodolfo Piske <an...@gmail.com>
AuthorDate: Fri Oct 27 16:50:01 2023 +0200

    (chores) camel-platform-http-vertx: break large methods
    
    This should help obtain better information when profiling the code
---
 .../http/vertx/VertxPlatformHttpConsumer.java      |  77 +++++---
 .../http/vertx/VertxPlatformHttpSupport.java       | 220 ++++++++++++---------
 2 files changed, 175 insertions(+), 122 deletions(-)

diff --git a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpConsumer.java b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpConsumer.java
index 2a3c91e03c2..708e0a86e25 100644
--- a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpConsumer.java
+++ b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpConsumer.java
@@ -155,8 +155,7 @@ public class VertxPlatformHttpConsumer extends DefaultConsumer implements Suspen
 
     protected void handleRequest(RoutingContext ctx) {
         if (isSuspended()) {
-            ctx.response().setStatusCode(503);
-            ctx.end();
+            handleSuspend(ctx);
             return;
         }
 
@@ -181,10 +180,7 @@ public class VertxPlatformHttpConsumer extends DefaultConsumer implements Suspen
         //
 
         if (getEndpoint().isHttpProxy()) {
-            exchange.getExchangeExtension().setStreamCacheDisabled(true);
-            final MultiMap httpHeaders = ctx.request().headers();
-            exchange.getMessage().setHeader(Exchange.HTTP_HOST, httpHeaders.get("Host"));
-            exchange.getMessage().removeHeader("Proxy-Connection");
+            handleProxy(ctx, exchange);
         }
 
         vertx.executeBlocking(() -> {
@@ -218,6 +214,18 @@ public class VertxPlatformHttpConsumer extends DefaultConsumer implements Suspen
                 });
     }
 
+    private static void handleSuspend(RoutingContext ctx) {
+        ctx.response().setStatusCode(503);
+        ctx.end();
+    }
+
+    private static void handleProxy(RoutingContext ctx, Exchange exchange) {
+        exchange.getExchangeExtension().setStreamCacheDisabled(true);
+        final MultiMap httpHeaders = ctx.request().headers();
+        exchange.getMessage().setHeader(Exchange.HTTP_HOST, httpHeaders.get("Host"));
+        exchange.getMessage().removeHeader("Proxy-Connection");
+    }
+
     protected Exchange toExchange(RoutingContext ctx) {
         final Exchange exchange = createExchange(false);
         exchange.setPattern(ExchangePattern.InOut);
@@ -251,34 +259,45 @@ public class VertxPlatformHttpConsumer extends DefaultConsumer implements Suspen
         populateCamelHeaders(ctx, result.getHeaders(), exchange, headerFilterStrategy);
         final String mimeType = ctx.parsedHeaders().contentType().value();
         final boolean isMultipartFormData = "multipart/form-data".equals(mimeType);
+
         if ("application/x-www-form-urlencoded".equals(mimeType) || isMultipartFormData) {
-            final MultiMap formData = ctx.request().formAttributes();
-            final Map<String, Object> body = new HashMap<>();
-            for (String key : formData.names()) {
-                for (String value : formData.getAll(key)) {
-                    if (headerFilterStrategy != null
-                            && !headerFilterStrategy.applyFilterToExternalHeaders(key, value, exchange)) {
-                        appendHeader(result.getHeaders(), key, value);
-                        appendHeader(body, key, value);
-                    }
+            populateMultiFormData(ctx, exchange, result, headerFilterStrategy, isMultipartFormData);
+        } else {
+            populateDefaultMessage(ctx, result);
+        }
+    }
+
+    private static void populateDefaultMessage(RoutingContext ctx, Message result) {
+        final RequestBody requestBody = ctx.body();
+        final Buffer body = requestBody.buffer();
+        if (body != null) {
+            result.setBody(body);
+        } else {
+            result.setBody(null);
+        }
+    }
+
+    private void populateMultiFormData(
+            RoutingContext ctx, Exchange exchange, Message result, HeaderFilterStrategy headerFilterStrategy,
+            boolean isMultipartFormData) {
+        final MultiMap formData = ctx.request().formAttributes();
+        final Map<String, Object> body = new HashMap<>();
+        for (String key : formData.names()) {
+            for (String value : formData.getAll(key)) {
+                if (headerFilterStrategy != null
+                        && !headerFilterStrategy.applyFilterToExternalHeaders(key, value, exchange)) {
+                    appendHeader(result.getHeaders(), key, value);
+                    appendHeader(body, key, value);
                 }
             }
+        }
 
-            if (!body.isEmpty()) {
-                result.setBody(body);
-            }
+        if (!body.isEmpty()) {
+            result.setBody(body);
+        }
 
-            if (isMultipartFormData) {
-                populateAttachments(ctx.fileUploads(), result);
-            }
-        } else {
-            final RequestBody requestBody = ctx.body();
-            final Buffer body = requestBody.buffer();
-            if (body != null) {
-                result.setBody(body);
-            } else {
-                result.setBody(null);
-            }
+        if (isMultipartFormData) {
+            populateAttachments(ctx.fileUploads(), result);
         }
     }
 
diff --git a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpSupport.java b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpSupport.java
index 0adf9e2215f..74cec0c62e1 100644
--- a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpSupport.java
+++ b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpSupport.java
@@ -45,6 +45,7 @@ import org.slf4j.LoggerFactory;
 
 public final class VertxPlatformHttpSupport {
     private static final Logger LOGGER = LoggerFactory.getLogger(VertxPlatformHttpSupport.class);
+    public static final String DEFAULT_CONTENT_TYPE_ON_EXCEPTION = "text/plain; charset=utf-8";
 
     private VertxPlatformHttpSupport() {
     }
@@ -53,68 +54,16 @@ public final class VertxPlatformHttpSupport {
             HttpServerResponse response, Message message, HeaderFilterStrategy headerFilterStrategy,
             boolean muteExceptions) {
         final Exchange exchange = message.getExchange();
-        final TypeConverter tc = exchange.getContext().getTypeConverter();
 
         final int code = determineResponseCode(exchange, message.getBody());
         response.setStatusCode(code);
 
         // copy headers from Message to Response
         if (headerFilterStrategy != null) {
-            for (Map.Entry<String, Object> entry : message.getHeaders().entrySet()) {
-                final String key = entry.getKey();
-                final Object value = entry.getValue();
-                // use an iterator as there can be multiple values. (must not use a delimiter)
-                final Iterator<?> it = ObjectHelper.createIterator(value, null, true);
-
-                String firstValue = null;
-                List<String> values = null;
-
-                while (it.hasNext()) {
-                    final String headerValue = tc.convertTo(String.class, it.next());
-                    if (headerValue != null && !headerFilterStrategy.applyFilterToCamelHeaders(key, headerValue, exchange)) {
-                        if (firstValue == null) {
-                            firstValue = headerValue;
-                        } else {
-                            if (values == null) {
-                                values = new ArrayList<>();
-                                values.add(firstValue);
-                            }
-                            values.add(headerValue);
-                        }
-                    }
-                }
-
-                if (values != null) {
-                    response.putHeader(key, values);
-                } else if (firstValue != null) {
-                    response.putHeader(key, firstValue);
-                }
-            }
+            copyMessageHeadersToResponse(response, message, headerFilterStrategy, exchange);
         }
 
-        Object body = message.getBody();
-        final Exception exception = exchange.getException();
-
-        if (exception != null) {
-            if (muteExceptions) {
-                body = ""; // do not include stacktrace in body
-                // force content type to be text/plain as that is what the stacktrace is
-                message.setHeader(Exchange.CONTENT_TYPE, "text/plain; charset=utf-8");
-            } else {
-                // we failed due an exception so print it as plain text
-                final StringWriter sw = new StringWriter();
-                final PrintWriter pw = new PrintWriter(sw);
-                exception.printStackTrace(pw);
-
-                // the body should then be the stacktrace
-                body = ByteBuffer.wrap(sw.toString().getBytes(StandardCharsets.UTF_8));
-                // force content type to be text/plain as that is what the stacktrace is
-                message.setHeader(Exchange.CONTENT_TYPE, "text/plain; charset=utf-8");
-            }
-
-            // and mark the exception as failure handled, as we handled it by returning it as the response
-            ExchangeHelper.setFailureHandled(exchange);
-        }
+        final Object body = getBody(message, muteExceptions, exchange);
 
         // set the content-length if it can be determined, or chunked encoding
         final Integer length = determineContentLength(body);
@@ -133,6 +82,80 @@ public final class VertxPlatformHttpSupport {
         return body;
     }
 
+    private static Object getBody(Message message, boolean muteExceptions, Exchange exchange) {
+        final Exception exception = exchange.getException();
+
+        if (exception != null) {
+            return handleExceptions(message, muteExceptions, exception, exchange);
+        }
+        return message.getBody();
+    }
+
+    private static Object handleExceptions(Message message, boolean muteExceptions, Exception exception, Exchange exchange) {
+        Object body;
+        if (muteExceptions) {
+            body = ""; // do not include stacktrace in body
+            // force content type to be text/plain as that is what the stacktrace is
+            message.setHeader(Exchange.CONTENT_TYPE, DEFAULT_CONTENT_TYPE_ON_EXCEPTION);
+        } else {
+            // we failed due an exception so print it as plain text
+            final StringWriter sw = new StringWriter();
+            final PrintWriter pw = new PrintWriter(sw);
+            exception.printStackTrace(pw);
+
+            // the body should then be the stacktrace
+            body = ByteBuffer.wrap(sw.toString().getBytes(StandardCharsets.UTF_8));
+            // force content type to be text/plain as that is what the stacktrace is
+            message.setHeader(Exchange.CONTENT_TYPE, DEFAULT_CONTENT_TYPE_ON_EXCEPTION);
+        }
+
+        // and mark the exception as failure handled, as we handled it by returning it as the response
+        ExchangeHelper.setFailureHandled(exchange);
+        return body;
+    }
+
+    private static void copyMessageHeadersToResponse(
+            HttpServerResponse response, Message message, HeaderFilterStrategy headerFilterStrategy, Exchange exchange) {
+        final TypeConverter tc = exchange.getContext().getTypeConverter();
+
+        for (Map.Entry<String, Object> entry : message.getHeaders().entrySet()) {
+            final String key = entry.getKey();
+            final Object value = entry.getValue();
+            // use an iterator as there can be multiple values. (must not use a delimiter)
+            final Iterator<?> it = ObjectHelper.createIterator(value, null, true);
+
+            putHeader(response, headerFilterStrategy, exchange, it, tc, key);
+        }
+    }
+
+    private static void putHeader(
+            HttpServerResponse response, HeaderFilterStrategy headerFilterStrategy, Exchange exchange, Iterator<?> it,
+            TypeConverter tc, String key) {
+        String firstValue = null;
+        List<String> values = null;
+
+        while (it.hasNext()) {
+            final String headerValue = tc.convertTo(String.class, it.next());
+            if (headerValue != null && !headerFilterStrategy.applyFilterToCamelHeaders(key, headerValue, exchange)) {
+                if (firstValue == null) {
+                    firstValue = headerValue;
+                } else {
+                    if (values == null) {
+                        values = new ArrayList<>();
+                        values.add(firstValue);
+                    }
+                    values.add(headerValue);
+                }
+            }
+        }
+
+        if (values != null) {
+            response.putHeader(key, values);
+        } else if (firstValue != null) {
+            response.putHeader(key, firstValue);
+        }
+    }
+
     static Integer determineContentLength(Object body) {
         if (body instanceof byte[]) {
             return ((byte[]) body).length;
@@ -219,35 +242,7 @@ public final class VertxPlatformHttpSupport {
         headersMap.put(Exchange.HTTP_PATH, ctx.normalizedPath());
 
         if (headerFilterStrategy != null) {
-            final MultiMap requestHeaders = request.headers();
-            final String authz = requestHeaders.get("authorization");
-            // store a special header that this request was authenticated using HTTP Basic
-            if (authz != null && authz.trim().startsWith("Basic")) {
-                if (!headerFilterStrategy.applyFilterToExternalHeaders(Exchange.AUTHENTICATION, "Basic", exchange)) {
-                    appendHeader(headersMap, Exchange.AUTHENTICATION, "Basic");
-                }
-            }
-            for (String name : requestHeaders.names()) {
-                // add the headers one by one, and use the header filter strategy
-                for (String value : requestHeaders.getAll(name)) {
-                    if (!headerFilterStrategy.applyFilterToExternalHeaders(name.toString(), value, exchange)) {
-                        appendHeader(headersMap, name.toString(), value);
-                    }
-                }
-            }
-
-            // process uri parameters as headers
-            final MultiMap pathParameters = ctx.queryParams();
-            // continue if the map is not empty, otherwise there are no params
-            if (!pathParameters.isEmpty()) {
-                for (String name : pathParameters.names()) {
-                    for (String value : pathParameters.getAll(name)) {
-                        if (!headerFilterStrategy.applyFilterToExternalHeaders(name, value, exchange)) {
-                            appendHeader(headersMap, name, value);
-                        }
-                    }
-                }
-            }
+            applyHeaderFilterStrategy(ctx, headersMap, exchange, headerFilterStrategy, request);
         }
 
         // Path parameters
@@ -275,21 +270,60 @@ public final class VertxPlatformHttpSupport {
         headersMap.put(Exchange.HTTP_RAW_QUERY, request.query());
     }
 
+    private static void applyHeaderFilterStrategy(
+            RoutingContext ctx, Map<String, Object> headersMap, Exchange exchange, HeaderFilterStrategy headerFilterStrategy,
+            HttpServerRequest request) {
+        final MultiMap requestHeaders = request.headers();
+        final String authz = requestHeaders.get("authorization");
+        // store a special header that this request was authenticated using HTTP Basic
+        if (authz != null && authz.trim().startsWith("Basic")) {
+            if (!headerFilterStrategy.applyFilterToExternalHeaders(Exchange.AUTHENTICATION, "Basic", exchange)) {
+                appendHeader(headersMap, Exchange.AUTHENTICATION, "Basic");
+            }
+        }
+        for (String name : requestHeaders.names()) {
+            // add the headers one by one, and use the header filter strategy
+            for (String value : requestHeaders.getAll(name)) {
+                if (!headerFilterStrategy.applyFilterToExternalHeaders(name, value, exchange)) {
+                    appendHeader(headersMap, name, value);
+                }
+            }
+        }
+
+        // process uri parameters as headers
+        final MultiMap pathParameters = ctx.queryParams();
+        // continue if the map is not empty, otherwise there are no params
+        if (!pathParameters.isEmpty()) {
+            for (String name : pathParameters.names()) {
+                for (String value : pathParameters.getAll(name)) {
+                    if (!headerFilterStrategy.applyFilterToExternalHeaders(name, value, exchange)) {
+                        appendHeader(headersMap, name, value);
+                    }
+                }
+            }
+        }
+    }
+
     @SuppressWarnings("unchecked")
     static void appendHeader(Map<String, Object> headers, String key, Object value) {
         if (headers.containsKey(key)) {
-            Object existing = headers.get(key);
-            List<Object> list;
-            if (existing instanceof List) {
-                list = (List<Object>) existing;
-            } else {
-                list = new ArrayList<>();
-                list.add(existing);
-            }
-            list.add(value);
-            value = list;
+            value = addToList(headers, key, value);
         }
 
         headers.put(key, value);
     }
+
+    private static Object addToList(Map<String, Object> headers, String key, Object value) {
+        Object existing = headers.get(key);
+        List<Object> list;
+        if (existing instanceof List) {
+            list = (List<Object>) existing;
+        } else {
+            list = new ArrayList<>();
+            list.add(existing);
+        }
+        list.add(value);
+        value = list;
+        return value;
+    }
 }


(camel) 02/02: (chores) camel-core: break large methods

Posted by or...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

orpiske pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 9b59f350f6bc6718145529426e8e2d2e5e15bc45
Author: Otavio Rodolfo Piske <an...@gmail.com>
AuthorDate: Fri Oct 27 16:50:13 2023 +0200

    (chores) camel-core: break large methods
    
    This should help obtain better information when profiling the code
---
 .../camel/support/DefaultHeaderFilterStrategy.java |  77 +++++---
 .../org/apache/camel/support/ObjectHelper.java     | 216 ++++++++++++---------
 2 files changed, 168 insertions(+), 125 deletions(-)

diff --git a/core/camel-support/src/main/java/org/apache/camel/support/DefaultHeaderFilterStrategy.java b/core/camel-support/src/main/java/org/apache/camel/support/DefaultHeaderFilterStrategy.java
index eb091d31ad2..7a99e29ab16 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/DefaultHeaderFilterStrategy.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/DefaultHeaderFilterStrategy.java
@@ -309,47 +309,68 @@ public class DefaultHeaderFilterStrategy implements HeaderFilterStrategy {
         }
 
         if (startsWith != null) {
-            for (String s : startsWith) {
-                boolean match = headerName.startsWith(s);
-                if (match) {
-                    return filterOnMatch;
-                }
+            if (tryHeaderMatch(headerName, startsWith)) {
+                return filterOnMatch;
             }
         }
 
         if (pattern != null) {
-            // optimize if its the default pattern as we know the pattern is to check for keys starting with Camel
-            if (pattern == CAMEL_FILTER_PATTERN) {
-                boolean match = headerName.startsWith("Camel") || headerName.startsWith("camel")
-                        || headerName.startsWith("org.apache.camel.");
-                if (match) {
-                    return filterOnMatch;
-                }
-            } else if (pattern.matcher(headerName).matches()) {
+            if (tryPattern(headerName, pattern)) {
                 return filterOnMatch;
             }
         }
 
         if (filter != null) {
-            if (isCaseInsensitive()) {
-                for (String filterString : filter) {
-                    if (filterString.equalsIgnoreCase(headerName)) {
-                        return filterOnMatch;
-                    }
-                }
-            } else if (isLowerCase()) {
-                String lower = headerName.toLowerCase(Locale.ENGLISH);
-                if (filter.contains(lower)) {
-                    return filterOnMatch;
-                }
-            } else {
-                if (filter.contains(headerName)) {
-                    return filterOnMatch;
-                }
+            if (evalFilterMatch(headerName, filter)) {
+                return filterOnMatch;
             }
         }
 
         return extendedFilter(direction, headerName, headerValue, exchange);
     }
 
+    private boolean tryPattern(String headerName, Pattern pattern) {
+        // optimize if its the default pattern as we know the pattern is to check for keys starting with Camel
+        if (pattern == CAMEL_FILTER_PATTERN) {
+            boolean match = headerName.startsWith("Camel") || headerName.startsWith("camel")
+                    || headerName.startsWith("org.apache.camel.");
+            if (match) {
+                return true;
+            }
+        } else if (pattern.matcher(headerName).matches()) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean tryHeaderMatch(String headerName, String[] startsWith) {
+        for (String s : startsWith) {
+            boolean match = headerName.startsWith(s);
+            if (match) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean evalFilterMatch(String headerName, Set<String> filter) {
+        if (isCaseInsensitive()) {
+            for (String filterString : filter) {
+                if (filterString.equalsIgnoreCase(headerName)) {
+                    return true;
+                }
+            }
+        } else if (isLowerCase()) {
+            String lower = headerName.toLowerCase(Locale.ENGLISH);
+            if (filter.contains(lower)) {
+                return true;
+            }
+        } else {
+            if (filter.contains(headerName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
 }
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 8d18cd513d8..33526c2c926 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
@@ -782,6 +782,8 @@ public final class ObjectHelper {
 
         if (value == null) {
             return Collections.emptyList();
+        } else if (value instanceof String) {
+            return createStringIterator((String) value, delimiter, allowEmptyValues, pattern);
         } else if (value instanceof Iterator) {
             final Iterator<Object> iterator = (Iterator<Object>) value;
             return (Iterable<Object>) () -> iterator;
@@ -791,116 +793,136 @@ public final class ObjectHelper {
             Map<?, ?> map = (Map<?, ?>) value;
             return map.entrySet();
         } else if (value.getClass().isArray()) {
-            if (org.apache.camel.util.ObjectHelper.isPrimitiveArrayType(value.getClass())) {
-                final Object array = value;
-                return (Iterable<Object>) () -> new Iterator<>() {
-                    private int idx;
+            return createArrayIterator(value);
+        } else if (value instanceof NodeList) {
+            // lets iterate through DOM results after performing XPaths
+            final NodeList nodeList = (NodeList) value;
+            return (Iterable<Node>) () -> createNodeListIterator(nodeList);
+        } else {
+            return Collections.singletonList(value);
+        }
+    }
 
-                    public boolean hasNext() {
-                        return idx < Array.getLength(array);
-                    }
+    private static Iterable<Object> createArrayIterator(Object value) {
+        if (org.apache.camel.util.ObjectHelper.isPrimitiveArrayType(value.getClass())) {
+            final Object array = value;
+            return () -> createPrimitiveArrayIterator(array);
+        } else {
+            return Arrays.asList((Object[]) value);
+        }
+    }
 
-                    public Object next() {
-                        if (!hasNext()) {
-                            throw new NoSuchElementException(
-                                    "no more element available for '" + array + "' at the index " + idx);
-                        }
+    private static Iterable<?> createStringIterator(String value, String delimiter, boolean allowEmptyValues, boolean pattern) {
+        final String s = value;
 
-                        return Array.get(array, idx++);
-                    }
+        // this code is optimized to only use a Scanner if needed, eg there is a delimiter
 
-                    @Override
-                    public void remove() {
-                        throw new UnsupportedOperationException();
-                    }
-                };
-            } else {
-                return Arrays.asList((Object[]) value);
+        if (delimiter != null && (pattern || s.contains(delimiter))) {
+            // if its the default delimiter and the value has parenthesis
+            if (DEFAULT_DELIMITER.equals(delimiter)) {
+                return createDelimitedStringIterator(s);
+            } else if (pattern) {
+                return (Iterable<String>) () -> new StringIteratorForPattern(s, delimiter);
             }
-        } else if (value instanceof NodeList) {
-            // lets iterate through DOM results after performing XPaths
-            final NodeList nodeList = (NodeList) value;
-            return (Iterable<Node>) () -> new Iterator<>() {
-                private int idx;
+            return (Iterable<String>) () -> new StringIterator(s, delimiter);
+        } else {
+            return (Iterable<Object>) () -> createPlainIterator(allowEmptyValues, s);
+        }
+    }
 
-                public boolean hasNext() {
-                    return idx < nodeList.getLength();
-                }
+    private static Iterable<String> createDelimitedStringIterator(String s) {
+        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 (Iterable<String>) () -> StringHelper.splitOnCharacterAsIterator(s, DEFAULT_DELIMITER_CHAR,
+                    count);
+        }
+    }
 
-                public Node next() {
-                    if (!hasNext()) {
-                        throw new NoSuchElementException(
-                                "no more element available for '" + nodeList + "' at the index " + idx);
-                    }
+    private static Iterator<Object> createPlainIterator(boolean allowEmptyValues, String s) {
+        // use a plain iterator that returns the value as is as there are only a single value
+        return new Iterator<>() {
+            private int idx;
 
-                    return nodeList.item(idx++);
+            public boolean hasNext() {
+                return idx == 0 && (allowEmptyValues || org.apache.camel.util.ObjectHelper.isNotEmpty(s));
+            }
+
+            public Object next() {
+                if (!hasNext()) {
+                    throw new NoSuchElementException(
+                            "no more element available for '" + s + "' at the index " + idx);
                 }
 
-                @Override
-                public void remove() {
-                    throw new UnsupportedOperationException();
+                idx++;
+                return s;
+            }
+
+            @Override
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    private static Iterator<Node> createNodeListIterator(NodeList nodeList) {
+        return new Iterator<>() {
+            private int idx;
+
+            public boolean hasNext() {
+                return idx < nodeList.getLength();
+            }
+
+            public Node next() {
+                if (!hasNext()) {
+                    throw new NoSuchElementException(
+                            "no more element available for '" + nodeList + "' at the index " + idx);
                 }
-            };
-        } else if (value instanceof String) {
-            final String s = (String) value;
-
-            // 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)) {
-                    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 (Iterable<String>) () -> StringHelper.splitOnCharacterAsIterator(s, DEFAULT_DELIMITER_CHAR,
-                                count);
-                    }
-                } else if (pattern) {
-                    return (Iterable<String>) () -> new StringIteratorForPattern(s, delimiter);
+
+                return nodeList.item(idx++);
+            }
+
+            @Override
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    private static Iterator<Object> createPrimitiveArrayIterator(Object array) {
+        return new Iterator<>() {
+            private int idx;
+
+            public boolean hasNext() {
+                return idx < Array.getLength(array);
+            }
+
+            public Object next() {
+                if (!hasNext()) {
+                    throw new NoSuchElementException(
+                            "no more element available for '" + array + "' at the index " + idx);
                 }
-                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
-                    return new Iterator<>() {
-                        private int idx;
-
-                        public boolean hasNext() {
-                            return idx == 0 && (allowEmptyValues || org.apache.camel.util.ObjectHelper.isNotEmpty(s));
-                        }
-
-                        public Object next() {
-                            if (!hasNext()) {
-                                throw new NoSuchElementException(
-                                        "no more element available for '" + s + "' at the index " + idx);
-                            }
-
-                            idx++;
-                            return s;
-                        }
-
-                        @Override
-                        public void remove() {
-                            throw new UnsupportedOperationException();
-                        }
-                    };
-                };
+
+                return Array.get(array, idx++);
             }
-        } else {
-            return Collections.singletonList(value);
-        }
+
+            @Override
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
     }
 
     /**