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 18:14:26 UTC

(camel) branch main updated: CAMEL-18482: Split EIP - Allow to split in single mode. (#12576)

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

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


The following commit(s) were added to refs/heads/main by this push:
     new 17bbc6cae61 CAMEL-18482: Split EIP - Allow to split in single mode. (#12576)
17bbc6cae61 is described below

commit 17bbc6cae61efffef70ae3a916122e30c8e93f51
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Fri Dec 22 19:14:21 2023 +0100

    CAMEL-18482: Split EIP - Allow to split in single mode. (#12576)
    
    * CAMEL-18482: Split EIP - Allow to split in single mode.
    
    * CAMEL-18482: Split EIP - Allow to split in single mode.
    
    * CAMEL-18482: Split EIP - Allow to split in single mode.
---
 .../org/apache/camel/catalog/models/split.json     |  2 +-
 .../apache/camel/catalog/schemas/camel-spring.xsd  |  4 +-
 .../resources/org/apache/camel/model/split.json    |  2 +-
 .../org/apache/camel/model/SplitDefinition.java    |  7 +-
 .../camel/processor/RecipientListProcessor.java    |  4 --
 .../java/org/apache/camel/processor/Splitter.java  |  7 +-
 .../camel/processor/SplitterSingleMapTest.java     | 75 ++++++++++++++++++++++
 .../dsl/yaml/deserializers/ModelDeserializers.java |  2 +-
 .../generated/resources/schema/camelYamlDsl.json   |  2 +-
 9 files changed, 91 insertions(+), 14 deletions(-)

diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/split.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/split.json
index ed85cd1b120..63c0043e17e 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/split.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/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 use the value as a single list, this can be needed in some special situations. The default value is comma." },
     "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/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
index 7b8a5343810..938afd7e95e 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
@@ -12668,7 +12668,9 @@ Sets the comparator to use for sorting.
           <xs:annotation>
             <xs:documentation xml:lang="en">
 <![CDATA[
-Delimiter used in splitting messages. Can be turned off using the value false. The default value is ,. Default value: ,
+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 use the value as a single list, this can be needed in some special situations. The default value
+is comma. Default value: ,
 ]]>
             </xs:documentation>
           </xs:annotation>
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..63c0043e17e 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 use the value as a single list, this can be needed in some special situations. The default value is comma." },
     "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..de0b40653d2 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,9 +115,12 @@ 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 use the value as a single list,
+     * this can be needed in some special situations.
      * <p/>
-     * The default value is ,
+     * The default value is comma.
      *
      * @param  delimiter the delimiter
      * @return           the builder
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;
+        }
+    }
+}
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
index ec52adcc75e..d7f9c365f24 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
@@ -16431,7 +16431,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     @YamlProperty(name = "aggregationStrategy", type = "string", 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 (leave it unchanged). You can also use a POJO as the AggregationStrategy", displayName = "Aggregation Strategy"),
                     @YamlProperty(name = "aggregationStrategyMethodAllowNull", type = "boolean", 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 data to enrich), when using POJOs as the AggregationStrategy", displayName = "Aggregation Strategy Method Allow Null"),
                     @YamlProperty(name = "aggregationStrategyMethodName", type = "string", description = "This option can be used to explicit declare the method name to use, when using POJOs as the AggregationStrategy.", displayName = "Aggregation Strategy Method Name"),
-                    @YamlProperty(name = "delimiter", type = "string", defaultValue = ",", description = "Delimiter used in splitting messages. Can be turned off using the value false. The default value is ,", displayName = "Delimiter"),
+                    @YamlProperty(name = "delimiter", type = "string", 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 use the value as a single list, this can be needed in some special situations. The default value is comma.", displayName = "Delimiter"),
                     @YamlProperty(name = "description", type = "string", description = "Sets the description of this node", displayName = "Description"),
                     @YamlProperty(name = "disabled", type = "boolean", 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.", displayName = "Disabled"),
                     @YamlProperty(name = "executorService", type = "string", description = "To use a custom Thread Pool to be used for parallel processing. Notice if you set this option, then parallel processing is automatically implied, and you do not have to enable that option as well.", displayName = "Executor Service"),
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
index 6cab3898979..112a651e5ab 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
@@ -5969,7 +5969,7 @@
           "delimiter" : {
             "type" : "string",
             "title" : "Delimiter",
-            "description" : "Delimiter used in splitting messages. Can be turned off using the value false. The default value is ,",
+            "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 use the value as a single list, this can be needed in some special situations. The default value is comma.",
             "default" : ","
           },
           "description" : {