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

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

commit bd5e6fa7a8269330b4f455539aff05872d67d544
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Dec 18 07:54:35 2025 +0100

    CAMEL-22431: camel-once - A component for development to trigger only once
---
 .../org/apache/camel/catalog/components/once.json  |   6 +-
 .../component/once/OnceEndpointConfigurer.java     |  15 +++
 .../component/once/OnceEndpointUriFactory.java     |   9 +-
 .../org/apache/camel/component/once/once.json      |   6 +-
 .../apache/camel/component/once/OnceConsumer.java  |  28 +++--
 .../apache/camel/component/once/OnceEndpoint.java  |  34 +++++-
 .../endpoint/dsl/OnceEndpointBuilderFactory.java   | 126 ++++++++++++++++++---
 7 files changed, 196 insertions(+), 28 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/once.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/once.json
index 690afc34f39c..909c42b0f30e 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/once.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/once.json
@@ -30,9 +30,11 @@
   "properties": {
     "name": { "index": 0, "kind": "path", "displayName": "Name", "group": 
"consumer", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The logical name" },
     "body": { "index": 1, "kind": "parameter", "displayName": "Body", "group": 
"consumer", "label": "", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "supportFileReference": true, "description": "The data 
to use as message body. You can externalize the data by using file: or 
classpath: as prefix and specify the location of the file." },
-    "delay": { "index": 2, "kind": "parameter", "displayName": "Delay", 
"group": "consumer", "label": "", "required": false, "type": "integer", 
"javaType": "long", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 1000, "description": "The number of milliseconds to wait before 
triggering. The default value is 1000." },
+    "headers": { "index": 2, "kind": "parameter", "displayName": "Headers", 
"group": "consumer", "label": "", "required": false, "type": "object", 
"javaType": "java.util.Map<java.lang.String, java.lang.Object>", "prefix": 
"header.", "multiValue": true, "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "supportFileReference": true, 
"description": "The data to use as message headers as key=value pairs. You can 
externalize the data by using file: or classpath: [...]
     "bridgeErrorHandler": { "index": 3, "kind": "parameter", "displayName": 
"Bridge Error Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Allows for bridging the consumer to the 
Camel routing Error Handler, which mean any exceptions (if possible) occurred 
while the Camel consumer is trying to pickup incoming  [...]
     "exceptionHandler": { "index": 4, "kind": "parameter", "displayName": 
"Exception Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
let the consumer use a custom ExceptionHandler. Notice if the option 
bridgeErrorHandler is enabled then this option is not in use. By def [...]
-    "exchangePattern": { "index": 5, "kind": "parameter", "displayName": 
"Exchange Pattern", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "enum", "javaType": 
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], 
"deprecated": false, "autowired": false, "secret": false, "description": "Sets 
the exchange pattern when the consumer creates an exchange." }
+    "exchangePattern": { "index": 5, "kind": "parameter", "displayName": 
"Exchange Pattern", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "enum", "javaType": 
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], 
"deprecated": false, "autowired": false, "secret": false, "description": "Sets 
the exchange pattern when the consumer creates an exchange." },
+    "delay": { "index": 6, "kind": "parameter", "displayName": "Delay", 
"group": "advanced", "label": "advanced", "required": false, "type": "integer", 
"javaType": "long", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 1000, "description": "The number of milliseconds to wait before 
triggering. The default value is 1000." },
+    "variables": { "index": 7, "kind": "parameter", "displayName": 
"Variables", "group": "advanced", "label": "advanced", "required": false, 
"type": "object", "javaType": "java.util.Map<java.lang.String, 
java.lang.Object>", "prefix": "variable.", "multiValue": true, "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"supportFileReference": true, "description": "The data to use as exchange 
variables as key=value pairs. You can externalize the data by using fi [...]
   }
 }
diff --git 
a/components/camel-once/src/generated/java/org/apache/camel/component/once/OnceEndpointConfigurer.java
 
b/components/camel-once/src/generated/java/org/apache/camel/component/once/OnceEndpointConfigurer.java
index 629bf407ee8e..ab494fa200b2 100644
--- 
a/components/camel-once/src/generated/java/org/apache/camel/component/once/OnceEndpointConfigurer.java
+++ 
b/components/camel-once/src/generated/java/org/apache/camel/component/once/OnceEndpointConfigurer.java
@@ -31,6 +31,8 @@ public class OnceEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "exceptionHandler": 
target.setExceptionHandler(property(camelContext, 
org.apache.camel.spi.ExceptionHandler.class, value)); return true;
         case "exchangepattern":
         case "exchangePattern": 
target.setExchangePattern(property(camelContext, 
org.apache.camel.ExchangePattern.class, value)); return true;
+        case "headers": target.setHeaders(property(camelContext, 
java.util.Map.class, value)); return true;
+        case "variables": target.setVariables(property(camelContext, 
java.util.Map.class, value)); return true;
         default: return false;
         }
     }
@@ -46,6 +48,8 @@ public class OnceEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "exceptionHandler": return 
org.apache.camel.spi.ExceptionHandler.class;
         case "exchangepattern":
         case "exchangePattern": return org.apache.camel.ExchangePattern.class;
+        case "headers": return java.util.Map.class;
+        case "variables": return java.util.Map.class;
         default: return null;
         }
     }
@@ -62,6 +66,17 @@ public class OnceEndpointConfigurer extends 
PropertyConfigurerSupport implements
         case "exceptionHandler": return target.getExceptionHandler();
         case "exchangepattern":
         case "exchangePattern": return target.getExchangePattern();
+        case "headers": return target.getHeaders();
+        case "variables": return target.getVariables();
+        default: return null;
+        }
+    }
+
+    @Override
+    public Object getCollectionValueType(Object target, String name, boolean 
ignoreCase) {
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "headers": return java.lang.Object.class;
+        case "variables": return java.lang.Object.class;
         default: return null;
         }
     }
diff --git 
a/components/camel-once/src/generated/java/org/apache/camel/component/once/OnceEndpointUriFactory.java
 
b/components/camel-once/src/generated/java/org/apache/camel/component/once/OnceEndpointUriFactory.java
index 6d835449c5ce..7e9fc37d7a65 100644
--- 
a/components/camel-once/src/generated/java/org/apache/camel/component/once/OnceEndpointUriFactory.java
+++ 
b/components/camel-once/src/generated/java/org/apache/camel/component/once/OnceEndpointUriFactory.java
@@ -23,16 +23,21 @@ public class OnceEndpointUriFactory extends 
org.apache.camel.support.component.E
     private static final Set<String> SECRET_PROPERTY_NAMES;
     private static final Map<String, String> MULTI_VALUE_PREFIXES;
     static {
-        Set<String> props = new HashSet<>(6);
+        Set<String> props = new HashSet<>(8);
         props.add("body");
         props.add("bridgeErrorHandler");
         props.add("delay");
         props.add("exceptionHandler");
         props.add("exchangePattern");
+        props.add("headers");
         props.add("name");
+        props.add("variables");
         PROPERTY_NAMES = Collections.unmodifiableSet(props);
         SECRET_PROPERTY_NAMES = Collections.emptySet();
-        MULTI_VALUE_PREFIXES = Collections.emptyMap();
+        Map<String, String> prefixes = new HashMap<>(2);
+        prefixes.put("headers", "header.");
+        prefixes.put("variables", "variable.");
+        MULTI_VALUE_PREFIXES = Collections.unmodifiableMap(prefixes);
     }
 
     @Override
diff --git 
a/components/camel-once/src/generated/resources/META-INF/org/apache/camel/component/once/once.json
 
b/components/camel-once/src/generated/resources/META-INF/org/apache/camel/component/once/once.json
index 690afc34f39c..909c42b0f30e 100644
--- 
a/components/camel-once/src/generated/resources/META-INF/org/apache/camel/component/once/once.json
+++ 
b/components/camel-once/src/generated/resources/META-INF/org/apache/camel/component/once/once.json
@@ -30,9 +30,11 @@
   "properties": {
     "name": { "index": 0, "kind": "path", "displayName": "Name", "group": 
"consumer", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The logical name" },
     "body": { "index": 1, "kind": "parameter", "displayName": "Body", "group": 
"consumer", "label": "", "required": false, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "supportFileReference": true, "description": "The data 
to use as message body. You can externalize the data by using file: or 
classpath: as prefix and specify the location of the file." },
-    "delay": { "index": 2, "kind": "parameter", "displayName": "Delay", 
"group": "consumer", "label": "", "required": false, "type": "integer", 
"javaType": "long", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 1000, "description": "The number of milliseconds to wait before 
triggering. The default value is 1000." },
+    "headers": { "index": 2, "kind": "parameter", "displayName": "Headers", 
"group": "consumer", "label": "", "required": false, "type": "object", 
"javaType": "java.util.Map<java.lang.String, java.lang.Object>", "prefix": 
"header.", "multiValue": true, "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "supportFileReference": true, 
"description": "The data to use as message headers as key=value pairs. You can 
externalize the data by using file: or classpath: [...]
     "bridgeErrorHandler": { "index": 3, "kind": "parameter", "displayName": 
"Bridge Error Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Allows for bridging the consumer to the 
Camel routing Error Handler, which mean any exceptions (if possible) occurred 
while the Camel consumer is trying to pickup incoming  [...]
     "exceptionHandler": { "index": 4, "kind": "parameter", "displayName": 
"Exception Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
let the consumer use a custom ExceptionHandler. Notice if the option 
bridgeErrorHandler is enabled then this option is not in use. By def [...]
-    "exchangePattern": { "index": 5, "kind": "parameter", "displayName": 
"Exchange Pattern", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "enum", "javaType": 
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], 
"deprecated": false, "autowired": false, "secret": false, "description": "Sets 
the exchange pattern when the consumer creates an exchange." }
+    "exchangePattern": { "index": 5, "kind": "parameter", "displayName": 
"Exchange Pattern", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "enum", "javaType": 
"org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], 
"deprecated": false, "autowired": false, "secret": false, "description": "Sets 
the exchange pattern when the consumer creates an exchange." },
+    "delay": { "index": 6, "kind": "parameter", "displayName": "Delay", 
"group": "advanced", "label": "advanced", "required": false, "type": "integer", 
"javaType": "long", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": 1000, "description": "The number of milliseconds to wait before 
triggering. The default value is 1000." },
+    "variables": { "index": 7, "kind": "parameter", "displayName": 
"Variables", "group": "advanced", "label": "advanced", "required": false, 
"type": "object", "javaType": "java.util.Map<java.lang.String, 
java.lang.Object>", "prefix": "variable.", "multiValue": true, "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"supportFileReference": true, "description": "The data to use as exchange 
variables as key=value pairs. You can externalize the data by using fi [...]
   }
 }
diff --git 
a/components/camel-once/src/main/java/org/apache/camel/component/once/OnceConsumer.java
 
b/components/camel-once/src/main/java/org/apache/camel/component/once/OnceConsumer.java
index 96da3b1650b7..934c7b1f21f3 100644
--- 
a/components/camel-once/src/main/java/org/apache/camel/component/once/OnceConsumer.java
+++ 
b/components/camel-once/src/main/java/org/apache/camel/component/once/OnceConsumer.java
@@ -22,11 +22,9 @@ import java.util.TimerTask;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
-import org.apache.camel.Expression;
 import org.apache.camel.Processor;
 import org.apache.camel.StartupListener;
 import org.apache.camel.support.DefaultConsumer;
-import org.apache.camel.support.LanguageHelper;
 import org.apache.camel.support.ResourceHelper;
 import org.apache.camel.util.StringHelper;
 import org.slf4j.Logger;
@@ -86,8 +84,24 @@ public class OnceConsumer extends DefaultConsumer implements 
StartupListener {
         public void run() {
             Exchange exchange = createExchange(false);
             try {
-                String body = resolveData(endpoint.getBody());
+                Object body = resolveData(endpoint.getBody());
                 exchange.getMessage().setBody(body);
+                if (endpoint.getHeaders() != null) {
+                    for (var e : endpoint.getHeaders().entrySet()) {
+                        Object v = resolveData(e.getValue());
+                        if (v != null) {
+                            exchange.getMessage().setHeader(e.getKey(), v);
+                        }
+                    }
+                }
+                if (endpoint.getVariables() != null) {
+                    for (var e : endpoint.getVariables().entrySet()) {
+                        Object v = resolveData(e.getValue());
+                        if (v != null) {
+                            exchange.setVariable(e.getKey(), v);
+                        }
+                    }
+                }
                 getProcessor().process(exchange);
             } catch (Exception e) {
                 exchange.setException(e);
@@ -104,10 +118,10 @@ public class OnceConsumer extends DefaultConsumer 
implements StartupListener {
         }
     }
 
-    private String resolveData(String data) throws Exception {
-        String answer = data;
-        if (ResourceHelper.hasScheme(data)) {
-            try (InputStream is = 
ResourceHelper.resolveMandatoryResourceAsInputStream(camelContext, data)) {
+    private Object resolveData(Object data) throws Exception {
+        String answer = data instanceof String ? data.toString() : null;
+        if (ResourceHelper.hasScheme(answer)) {
+            try (InputStream is = 
ResourceHelper.resolveMandatoryResourceAsInputStream(camelContext, answer)) {
                 answer = 
camelContext.getTypeConverter().mandatoryConvertTo(String.class, is);
             }
         }
diff --git 
a/components/camel-once/src/main/java/org/apache/camel/component/once/OnceEndpoint.java
 
b/components/camel-once/src/main/java/org/apache/camel/component/once/OnceEndpoint.java
index ba1b07bfa729..997a22ef5a40 100644
--- 
a/components/camel-once/src/main/java/org/apache/camel/component/once/OnceEndpoint.java
+++ 
b/components/camel-once/src/main/java/org/apache/camel/component/once/OnceEndpoint.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.component.once;
 
+import java.util.Map;
+
 import org.apache.camel.Category;
 import org.apache.camel.Component;
 import org.apache.camel.Consumer;
@@ -35,11 +37,17 @@ public class OnceEndpoint extends DefaultEndpoint {
     @UriPath
     @Metadata(required = true)
     private String name;
-    @UriParam(defaultValue = "1000")
+    @UriParam(label = "advanced", defaultValue = "1000")
     private long delay = 1000;
     @UriParam
     @Metadata(supportFileReference = true)
     private String body;
+    @UriParam(multiValue = true, prefix = "header.")
+    @Metadata(supportFileReference = true)
+    private Map<String, Object> headers;
+    @UriParam(label = "advanced", multiValue = true, prefix = "variable.")
+    @Metadata(supportFileReference = true)
+    private Map<String, Object> variables;
 
     public OnceEndpoint() {
     }
@@ -106,4 +114,28 @@ public class OnceEndpoint extends DefaultEndpoint {
     public void setBody(String body) {
         this.body = body;
     }
+
+    /**
+     * The data to use as message headers as key=value pairs. You can 
externalize the data by using file: or classpath:
+     * as prefix and specify the location of the file.
+     */
+    public Map<String, Object> getHeaders() {
+        return headers;
+    }
+
+    public void setHeaders(Map<String, Object> headers) {
+        this.headers = headers;
+    }
+
+    public Map<String, Object> getVariables() {
+        return variables;
+    }
+
+    /**
+     * The data to use as exchange variables as key=value pairs. You can 
externalize the data by using file: or
+     * classpath: as prefix and specify the location of the file.
+     */
+    public void setVariables(Map<String, Object> variables) {
+        this.variables = variables;
+    }
 }
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OnceEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OnceEndpointBuilderFactory.java
index d4bac6603f14..ea1360cc8930 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OnceEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OnceEndpointBuilderFactory.java
@@ -64,35 +64,52 @@ public interface OnceEndpointBuilderFactory {
             return this;
         }
         /**
-         * The number of milliseconds to wait before triggering. The default
-         * value is 1000.
+         * The data to use as message headers as key=value pairs. You can
+         * externalize the data by using file: or classpath: as prefix and
+         * specify the location of the file. This is a multi-value option with
+         * prefix: header.
          * 
-         * The option is a: <code>long</code> type.
+         * This option can also be loaded from an existing file, by prefixing
+         * with file: or classpath: followed by the location of the file.
+         * 
+         * The option is a: <code>java.util.Map&lt;java.lang.String,
+         * java.lang.Object&gt;</code> type.
+         * The option is multivalued, and you can use the headers(String,
+         * Object) method to add a value (call the method multiple times to set
+         * more values).
          * 
-         * Default: 1000
          * Group: consumer
          * 
-         * @param delay the value to set
+         * @param key the option key
+         * @param value the option value
          * @return the dsl builder
          */
-        default OnceEndpointBuilder delay(long delay) {
-            doSetProperty("delay", delay);
+        default OnceEndpointBuilder headers(String key, Object value) {
+            doSetMultiValueProperty("headers", "header." + key, value);
             return this;
         }
         /**
-         * The number of milliseconds to wait before triggering. The default
-         * value is 1000.
+         * The data to use as message headers as key=value pairs. You can
+         * externalize the data by using file: or classpath: as prefix and
+         * specify the location of the file. This is a multi-value option with
+         * prefix: header.
          * 
-         * The option will be converted to a <code>long</code> type.
+         * This option can also be loaded from an existing file, by prefixing
+         * with file: or classpath: followed by the location of the file.
+         * 
+         * The option is a: <code>java.util.Map&lt;java.lang.String,
+         * java.lang.Object&gt;</code> type.
+         * The option is multivalued, and you can use the headers(String,
+         * Object) method to add a value (call the method multiple times to set
+         * more values).
          * 
-         * Default: 1000
          * Group: consumer
          * 
-         * @param delay the value to set
+         * @param values the values
          * @return the dsl builder
          */
-        default OnceEndpointBuilder delay(String delay) {
-            doSetProperty("delay", delay);
+        default OnceEndpointBuilder headers(Map values) {
+            doSetMultiValueProperties("headers", "header.", values);
             return this;
         }
     }
@@ -224,6 +241,87 @@ public interface OnceEndpointBuilderFactory {
             doSetProperty("exchangePattern", exchangePattern);
             return this;
         }
+        /**
+         * The number of milliseconds to wait before triggering. The default
+         * value is 1000.
+         * 
+         * The option is a: <code>long</code> type.
+         * 
+         * Default: 1000
+         * Group: advanced
+         * 
+         * @param delay the value to set
+         * @return the dsl builder
+         */
+        default AdvancedOnceEndpointBuilder delay(long delay) {
+            doSetProperty("delay", delay);
+            return this;
+        }
+        /**
+         * The number of milliseconds to wait before triggering. The default
+         * value is 1000.
+         * 
+         * The option will be converted to a <code>long</code> type.
+         * 
+         * Default: 1000
+         * Group: advanced
+         * 
+         * @param delay the value to set
+         * @return the dsl builder
+         */
+        default AdvancedOnceEndpointBuilder delay(String delay) {
+            doSetProperty("delay", delay);
+            return this;
+        }
+        /**
+         * The data to use as exchange variables as key=value pairs. You can
+         * externalize the data by using file: or classpath: as prefix and
+         * specify the location of the file. This is a multi-value option with
+         * prefix: variable.
+         * 
+         * This option can also be loaded from an existing file, by prefixing
+         * with file: or classpath: followed by the location of the file.
+         * 
+         * The option is a: <code>java.util.Map&lt;java.lang.String,
+         * java.lang.Object&gt;</code> type.
+         * The option is multivalued, and you can use the variables(String,
+         * Object) method to add a value (call the method multiple times to set
+         * more values).
+         * 
+         * Group: advanced
+         * 
+         * @param key the option key
+         * @param value the option value
+         * @return the dsl builder
+         */
+        default AdvancedOnceEndpointBuilder variables(String key, Object 
value) {
+            doSetMultiValueProperty("variables", "variable." + key, value);
+            return this;
+        }
+        /**
+         * The data to use as exchange variables as key=value pairs. You can
+         * externalize the data by using file: or classpath: as prefix and
+         * specify the location of the file. This is a multi-value option with
+         * prefix: variable.
+         * 
+         * This option can also be loaded from an existing file, by prefixing
+         * with file: or classpath: followed by the location of the file.
+         * 
+         * The option is a: <code>java.util.Map&lt;java.lang.String,
+         * java.lang.Object&gt;</code> type.
+         * The option is multivalued, and you can use the variables(String,
+         * Object) method to add a value (call the method multiple times to set
+         * more values).
+         * 
+         * Group: advanced
+         * 
+         * @param values the values
+         * @return the dsl builder
+         */
+        default AdvancedOnceEndpointBuilder variables(Map values) {
+            doSetMultiValueProperties("variables", "variable.", values);
+            return this;
+        }
     }
 
     public interface OnceBuilders {

Reply via email to