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

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

commit 25aca0dfd01670b18f5466cc2999dc34ad6509db
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Jun 26 10:41:14 2025 +0200

    CAMEL-22200: components that are resource endpoint based should have 
content cache true as default and make it configurable on component level.
---
 .../component/jte/JteComponentConfigurer.java      |  6 +++
 .../org/apache/camel/component/jte/jte.json        | 11 ++--
 .../camel/component/jte/JteCodeResolver.java       | 26 ++++++---
 .../apache/camel/component/jte/JteComponent.java   | 14 +++++
 .../apache/camel/component/jte/JteEndpoint.java    | 11 +++-
 .../org/apache/camel/component/jte/JteRefTest.java | 62 ++++++++++++++++++++++
 6 files changed, 117 insertions(+), 13 deletions(-)

diff --git 
a/components/camel-jte/src/generated/java/org/apache/camel/component/jte/JteComponentConfigurer.java
 
b/components/camel-jte/src/generated/java/org/apache/camel/component/jte/JteComponentConfigurer.java
index 0255dcd0845..458f2301e0d 100644
--- 
a/components/camel-jte/src/generated/java/org/apache/camel/component/jte/JteComponentConfigurer.java
+++ 
b/components/camel-jte/src/generated/java/org/apache/camel/component/jte/JteComponentConfigurer.java
@@ -29,6 +29,8 @@ public class JteComponentConfigurer extends 
PropertyConfigurerSupport implements
         case "allowTemplateFromHeader": 
target.setAllowTemplateFromHeader(property(camelContext, boolean.class, 
value)); return true;
         case "autowiredenabled":
         case "autowiredEnabled": 
target.setAutowiredEnabled(property(camelContext, boolean.class, value)); 
return true;
+        case "contentcache":
+        case "contentCache": target.setContentCache(property(camelContext, 
boolean.class, value)); return true;
         case "contenttype":
         case "contentType": target.setContentType(property(camelContext, 
gg.jte.ContentType.class, value)); return true;
         case "lazystartproducer":
@@ -50,6 +52,8 @@ public class JteComponentConfigurer extends 
PropertyConfigurerSupport implements
         case "allowTemplateFromHeader": return boolean.class;
         case "autowiredenabled":
         case "autowiredEnabled": return boolean.class;
+        case "contentcache":
+        case "contentCache": return boolean.class;
         case "contenttype":
         case "contentType": return gg.jte.ContentType.class;
         case "lazystartproducer":
@@ -72,6 +76,8 @@ public class JteComponentConfigurer extends 
PropertyConfigurerSupport implements
         case "allowTemplateFromHeader": return 
target.isAllowTemplateFromHeader();
         case "autowiredenabled":
         case "autowiredEnabled": return target.isAutowiredEnabled();
+        case "contentcache":
+        case "contentCache": return target.isContentCache();
         case "contenttype":
         case "contentType": return target.getContentType();
         case "lazystartproducer":
diff --git 
a/components/camel-jte/src/generated/resources/META-INF/org/apache/camel/component/jte/jte.json
 
b/components/camel-jte/src/generated/resources/META-INF/org/apache/camel/component/jte/jte.json
index 7d99557c103..bd67bc92018 100644
--- 
a/components/camel-jte/src/generated/resources/META-INF/org/apache/camel/component/jte/jte.json
+++ 
b/components/camel-jte/src/generated/resources/META-INF/org/apache/camel/component/jte/jte.json
@@ -26,11 +26,12 @@
   "componentProperties": {
     "allowContextMapAll": { "index": 0, "kind": "property", "displayName": 
"Allow Context Map All", "group": "producer", "label": "", "required": false, 
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": false, "description": "Sets whether the 
context map should allow access to all details. By default only the message 
body and headers can be accessed. This option can be enabled for full access to 
the current Exchange and Ca [...]
     "allowTemplateFromHeader": { "index": 1, "kind": "property", 
"displayName": "Allow Template From Header", "group": "producer", "label": "", 
"required": false, "type": "boolean", "javaType": "boolean", "deprecated": 
false, "autowired": false, "secret": false, "defaultValue": false, 
"description": "Whether to allow to use resource template from header or not 
(default false). Enabling this allows to specify dynamic templates via message 
header. However this can be seen as a potential se [...]
-    "contentType": { "index": 2, "kind": "property", "displayName": "Content 
Type", "group": "producer", "label": "", "required": false, "type": "object", 
"javaType": "gg.jte.ContentType", "enum": [ "Plain", "Html" ], "deprecated": 
false, "autowired": false, "secret": false, "defaultValue": "Plain", 
"description": "Content type the JTE engine should use." },
-    "lazyStartProducer": { "index": 3, "kind": "property", "displayName": 
"Lazy Start Producer", "group": "producer", "label": "producer", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Whether the producer should be started lazy (on the first message). By 
starting lazy you can use this to allow CamelContext and routes to startup in 
situations where a producer may otherwise fail [...]
-    "preCompile": { "index": 4, "kind": "property", "displayName": "Pre 
Compile", "group": "producer", "label": "", "required": false, "type": 
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": false, "description": "To speed up startup and 
rendering on your production server, it is possible to precompile all templates 
during the build. This way, the template engine can load each template's .class 
file directly without first compil [...]
-    "workDir": { "index": 5, "kind": "property", "displayName": "Work Dir", 
"group": "producer", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "jte-classes", "description": "Work directory 
where JTE will store compiled templates." },
-    "autowiredEnabled": { "index": 6, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching t [...]
+    "contentCache": { "index": 2, "kind": "property", "displayName": "Content 
Cache", "group": "producer", "label": "", "required": false, "type": "boolean", 
"javaType": "boolean", "deprecated": false, "autowired": false, "secret": 
false, "defaultValue": true, "description": "Sets whether to use resource 
content cache or not" },
+    "contentType": { "index": 3, "kind": "property", "displayName": "Content 
Type", "group": "producer", "label": "", "required": false, "type": "object", 
"javaType": "gg.jte.ContentType", "enum": [ "Plain", "Html" ], "deprecated": 
false, "autowired": false, "secret": false, "defaultValue": "Plain", 
"description": "Content type the JTE engine should use." },
+    "lazyStartProducer": { "index": 4, "kind": "property", "displayName": 
"Lazy Start Producer", "group": "producer", "label": "producer", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Whether the producer should be started lazy (on the first message). By 
starting lazy you can use this to allow CamelContext and routes to startup in 
situations where a producer may otherwise fail [...]
+    "preCompile": { "index": 5, "kind": "property", "displayName": "Pre 
Compile", "group": "producer", "label": "", "required": false, "type": 
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": false, "description": "To speed up startup and 
rendering on your production server, it is possible to precompile all templates 
during the build. This way, the template engine can load each template's .class 
file directly without first compil [...]
+    "workDir": { "index": 6, "kind": "property", "displayName": "Work Dir", 
"group": "producer", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": "jte-classes", "description": "Work directory 
where JTE will store compiled templates." },
+    "autowiredEnabled": { "index": 7, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching t [...]
   },
   "headers": {
     "CamelJteResourceUri": { "index": 0, "kind": "header", "displayName": "", 
"group": "producer", "label": "", "required": false, "javaType": "String", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "A URI for the template resource to use instead of the 
endpoint configured.", "constantName": 
"org.apache.camel.component.jte.JteConstants#JTE_RESOURCE_URI" },
diff --git 
a/components/camel-jte/src/main/java/org/apache/camel/component/jte/JteCodeResolver.java
 
b/components/camel-jte/src/main/java/org/apache/camel/component/jte/JteCodeResolver.java
index 0345c6c25e6..96adda8c918 100644
--- 
a/components/camel-jte/src/main/java/org/apache/camel/component/jte/JteCodeResolver.java
+++ 
b/components/camel-jte/src/main/java/org/apache/camel/component/jte/JteCodeResolver.java
@@ -23,15 +23,17 @@ import java.util.concurrent.ConcurrentHashMap;
 
 import gg.jte.CodeResolver;
 import org.apache.camel.CamelContext;
+import org.apache.camel.support.ResourceHelper;
 import org.apache.camel.util.IOHelper;
 
 /**
- * To load JTE templates from classpath
+ * To load JTE templates from Camel resources such as classpath
  */
 public class JteCodeResolver implements CodeResolver {
 
     private final CamelContext camelContext;
     private final Map<String, String> headerTemplates = new 
ConcurrentHashMap<>();
+    private final Map<String, String> pathMappings = new ConcurrentHashMap<>();
 
     public JteCodeResolver(CamelContext camelContext) {
         this.camelContext = camelContext;
@@ -43,17 +45,29 @@ public class JteCodeResolver implements CodeResolver {
         }
     }
 
+    public void addPathMapping(String name, String uri) {
+        if (name != null && uri != null) {
+            pathMappings.put(name, uri);
+        }
+    }
+
     @Override
     public String resolve(String name) {
         String answer = headerTemplates.remove(name);
         if (answer == null) {
-            InputStream is = 
camelContext.getClassResolver().loadResourceAsStream(name);
-            if (is != null) {
-                try {
+            String key = pathMappings.remove(name);
+            if (key != null) {
+                key = name + ":" + key;
+            } else {
+                key = name;
+            }
+            try {
+                InputStream is = 
ResourceHelper.resolveResourceAsInputStream(camelContext, key);
+                if (is != null) {
                     answer = IOHelper.loadText(is);
-                } catch (IOException e) {
-                    // ignore
                 }
+            } catch (IOException e) {
+                // ignore
             }
         }
         return answer;
diff --git 
a/components/camel-jte/src/main/java/org/apache/camel/component/jte/JteComponent.java
 
b/components/camel-jte/src/main/java/org/apache/camel/component/jte/JteComponent.java
index 6c7c250b888..9237871ef9c 100644
--- 
a/components/camel-jte/src/main/java/org/apache/camel/component/jte/JteComponent.java
+++ 
b/components/camel-jte/src/main/java/org/apache/camel/component/jte/JteComponent.java
@@ -43,6 +43,8 @@ public class JteComponent extends DefaultComponent {
     private boolean preCompile;
     @Metadata(defaultValue = "Plain")
     private ContentType contentType = ContentType.Plain;
+    @Metadata(defaultValue = "true", description = "Sets whether to use 
resource content cache or not")
+    private boolean contentCache;
     @Metadata
     private boolean allowTemplateFromHeader;
     @Metadata
@@ -53,6 +55,7 @@ public class JteComponent extends DefaultComponent {
         JteEndpoint endpoint = new JteEndpoint(uri, this, remaining);
         endpoint.setAllowTemplateFromHeader(allowTemplateFromHeader);
         endpoint.setAllowContextMapAll(allowContextMapAll);
+        endpoint.setContentCache(contentCache);
 
         setProperties(endpoint, parameters);
 
@@ -134,6 +137,17 @@ public class JteComponent extends DefaultComponent {
         this.contentType = contentType;
     }
 
+    public boolean isContentCache() {
+        return contentCache;
+    }
+
+    /**
+     * Sets whether to use resource content cache or not
+     */
+    public void setContentCache(boolean contentCache) {
+        this.contentCache = contentCache;
+    }
+
     public boolean isAllowTemplateFromHeader() {
         return allowTemplateFromHeader;
     }
diff --git 
a/components/camel-jte/src/main/java/org/apache/camel/component/jte/JteEndpoint.java
 
b/components/camel-jte/src/main/java/org/apache/camel/component/jte/JteEndpoint.java
index 2338a41db0a..41e3f430d86 100644
--- 
a/components/camel-jte/src/main/java/org/apache/camel/component/jte/JteEndpoint.java
+++ 
b/components/camel-jte/src/main/java/org/apache/camel/component/jte/JteEndpoint.java
@@ -26,7 +26,9 @@ import org.apache.camel.component.ResourceEndpoint;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
 import org.apache.camel.support.ExchangeHelper;
+import org.apache.camel.support.ResourceHelper;
 import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.StringHelper;
 
 /**
  * Transform messages using a Java based template engine (JTE).
@@ -35,7 +37,7 @@ import org.apache.camel.util.ObjectHelper;
              remote = false, producerOnly = true, category = { 
Category.TRANSFORMATION }, headersClass = JteConstants.class)
 public class JteEndpoint extends ResourceEndpoint {
 
-    @UriParam(defaultValue = "false")
+    @UriParam
     private boolean allowTemplateFromHeader;
 
     public JteEndpoint() {
@@ -92,6 +94,7 @@ public class JteEndpoint extends ResourceEndpoint {
             }
         }
 
+        JteCodeResolver codeResolver = getComponent().getCodeResolver();
         String name = getResourceUri();
         String content;
         if (allowTemplateFromHeader) {
@@ -100,12 +103,16 @@ public class JteEndpoint extends ResourceEndpoint {
                 // remove the header to avoid it being propagated in the 
routing
                 exchange.getIn().removeHeader(JteConstants.JTE_TEMPLATE);
                 // add template in code resolver so we can find it
-                JteCodeResolver codeResolver = 
getComponent().getCodeResolver();
                 if (codeResolver != null) {
                     name = exchange.getExchangeId();
                     codeResolver.addTemplateFromHeader(name, content);
                 }
             }
+        } else if (ResourceHelper.hasScheme(name)) {
+            // name should not include scheme
+            String uri = StringHelper.after(name, ":");
+            name = StringHelper.before(name, ":");
+            codeResolver.addPathMapping(name, uri);
         }
         Object dataModel = null;
         if (allowTemplateFromHeader) {
diff --git 
a/components/camel-jte/src/test/java/org/apache/camel/component/jte/JteRefTest.java
 
b/components/camel-jte/src/test/java/org/apache/camel/component/jte/JteRefTest.java
new file mode 100644
index 00000000000..891673ab269
--- /dev/null
+++ 
b/components/camel-jte/src/test/java/org/apache/camel/component/jte/JteRefTest.java
@@ -0,0 +1,62 @@
+/*
+ * 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.component.jte;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class JteRefTest extends CamelTestSupport {
+
+    private static final String TEMP = """
+            @import org.apache.camel.component.jte.Model
+            @param Model model
+
+            Hello ${model.header("name")}. You ordered item 
${model.exchangeProperty("item")} on ${model.strBody()}.
+            """;
+
+    @Test
+    public void testRef() {
+        Exchange exchange = template.request("direct:a", new Processor() {
+            @Override
+            public void process(Exchange exchange) {
+                exchange.getIn().setBody("Tuesday");
+                exchange.getIn().setHeader("name", "Christian");
+                exchange.setProperty("item", "8");
+            }
+        });
+
+        assertEquals("Hello Christian. You ordered item 8 on Tuesday.", 
exchange.getMessage().getBody());
+        assertEquals("Christian", exchange.getMessage().getHeader("name"));
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                context.getRegistry().bind("mytemp", TEMP);
+
+                from("direct:a").to(
+                        "jte:ref:mytemp?allowContextMapAll=true");
+            }
+        };
+    }
+}

Reply via email to