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 2023/12/22 13:12:01 UTC

(camel) 01/01: CAMEL-18482: Split EIP - Allow to split in single mode.

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

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

commit a87a4d2f354c975471dc54d4a72af85169de3a1d
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Dec 22 14:11:48 2023 +0100

    CAMEL-18482: Split EIP - Allow to split in single mode.
---
 .../resources/org/apache/camel/model/split.json    |  2 +-
 .../org/apache/camel/model/SplitDefinition.java    |  5 +-
 .../camel/processor/RecipientListProcessor.java    |  4 --
 .../java/org/apache/camel/processor/Splitter.java  |  7 +-
 .../camel/processor/SplitterSingleMapTest.java     | 75 ++++++++++++++++++++++
 5 files changed, 84 insertions(+), 9 deletions(-)

diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/split.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/split.json
index ed85cd1b120..f792fe57945 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/split.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/split.json
@@ -16,7 +16,7 @@
     "description": { "index": 1, "kind": "element", "displayName": "Description", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" },
     "disabled": { "index": 2, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
     "expression": { "index": 3, "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "java", "joor", "jq", "js", "jsonpath", "language", "method", "mvel", "ognl", "python", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "sec [...]
-    "delimiter": { "index": 4, "kind": "attribute", "displayName": "Delimiter", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": ",", "description": "Delimiter used in splitting messages. Can be turned off using the value false. The default value is ," },
+    "delimiter": { "index": 4, "kind": "attribute", "displayName": "Delimiter", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": ",", "description": "Delimiter used in splitting messages. Can be turned off using the value false. To force not splitting then the delimiter can be set to single to thread the value as a single list, this can be used in special situations. The default value is ," },
     "aggregationStrategy": { "index": 5, "kind": "attribute", "displayName": "Aggregation Strategy", "required": false, "type": "object", "javaType": "org.apache.camel.AggregationStrategy", "deprecated": false, "autowired": false, "secret": false, "description": "Sets a reference to the AggregationStrategy to be used to assemble the replies from the split messages, into a single outgoing message from the Splitter. By default Camel will use the original incoming message to the splitter (l [...]
     "aggregationStrategyMethodName": { "index": 6, "kind": "attribute", "displayName": "Aggregation Strategy Method Name", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "This option can be used to explicit declare the method name to use, when using POJOs as the AggregationStrategy." },
     "aggregationStrategyMethodAllowNull": { "index": 7, "kind": "attribute", "displayName": "Aggregation Strategy Method Allow Null", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "If this option is false then the aggregate method is not used if there was no data to enrich. If this option is true then null values is used as the oldExchange (when no [...]
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/SplitDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/SplitDefinition.java
index 59b6b9d141d..5a28d2f8317 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/SplitDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/SplitDefinition.java
@@ -115,7 +115,10 @@ public class SplitDefinition extends OutputExpressionNode implements ExecutorSer
     // -------------------------------------------------------------------------
 
     /**
-     * Delimiter used in splitting messages. Can be turned off using the value <tt>false</tt>.
+     * Delimiter used in splitting messages.
+     * Can be turned off using the value <tt>false</tt>.
+     * To force not splitting then the delimiter can be set to <tt>single</tt> to thread the value as a single list,
+     * this can be used in special situations.
      * <p/>
      * The default value is ,
      *
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/RecipientListProcessor.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/RecipientListProcessor.java
index 4bf1ba68211..3cacec99784 100644
--- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/RecipientListProcessor.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/RecipientListProcessor.java
@@ -394,10 +394,6 @@ public class RecipientListProcessor extends MulticastProcessor {
     protected void doBuild() throws Exception {
         super.doBuild();
         ServiceHelper.buildService(producerCache);
-
-        // eager load classes
-        Object dummy = new RecipientProcessorExchangePair(0, null, null, null, null, null, null, false);
-        LOG.trace("Loaded {}", dummy.getClass().getName());
     }
 
     @Override
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/Splitter.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/Splitter.java
index 9eae71aac03..66df200c9ad 100644
--- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/Splitter.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/Splitter.java
@@ -59,6 +59,7 @@ public class Splitter extends MulticastProcessor implements AsyncProcessor, Trac
     private static final Logger LOG = LoggerFactory.getLogger(Splitter.class);
 
     private static final String IGNORE_DELIMITER_MARKER = "false";
+    private static final String SINGLE_DELIMITER_MARKER = "single";
     private final Expression expression;
     private final String delimiter;
 
@@ -95,9 +96,6 @@ public class Splitter extends MulticastProcessor implements AsyncProcessor, Trac
     @Override
     protected void doBuild() throws Exception {
         super.doBuild();
-        // eager load classes
-        Object dummy = new SplitterIterable();
-        LOG.trace("Loaded {}", dummy.getClass().getName());
     }
 
     @Override
@@ -189,6 +187,9 @@ public class Splitter extends MulticastProcessor implements AsyncProcessor, Trac
 
             if (IGNORE_DELIMITER_MARKER.equalsIgnoreCase(delimiter)) {
                 this.iterator = ObjectHelper.createIterator(value, null);
+            } else if (SINGLE_DELIMITER_MARKER.equalsIgnoreCase(delimiter)) {
+                // force single element
+                this.iterator = ObjectHelper.createIterator(List.of(value));
             } else {
                 this.iterator = ObjectHelper.createIterator(value, delimiter);
             }
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/SplitterSingleMapTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/SplitterSingleMapTest.java
new file mode 100644
index 00000000000..ff12d7c2b55
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/SplitterSingleMapTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.processor;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.jupiter.api.Test;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class SplitterSingleMapTest extends ContextTestSupport {
+
+    @Test
+    public void testSplitSingleMap() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:line");
+        mock.expectedMessageCount(1);
+        mock.message(0).body().isInstanceOf(Map.class);
+
+        Map<String, String> map = new LinkedHashMap<>();
+        map.put("123", "Hello World");
+        map.put("789", "Bye World");
+
+        template.sendBody("direct:start", new Order(44, map));
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .split(simple("${body.data}"), "single")
+                        .to("mock:line")
+                    .end();
+            }
+        };
+    }
+
+    private static class Order {
+
+        private final int id;
+        private final Map<String, String> data;
+
+        public Order(int id, Map<String, String> data) {
+            this.id = id;
+            this.data = data;
+        }
+
+        public int getId() {
+            return id;
+        }
+
+        public Map<String, String> getData() {
+            return data;
+        }
+    }
+}