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/25 10:30:13 UTC

(camel) branch jte created (now 1d180c01319)

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

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


      at 1d180c01319 CAMEL-15570: camel-jte component

This branch includes the following new commits:

     new 1d180c01319 CAMEL-15570: camel-jte component

The 1 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.



(camel) 01/01: CAMEL-15570: camel-jte component

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

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

commit 1d180c013192209b9d779ba83f23479895bac8c5
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Dec 25 11:29:56 2023 +0100

    CAMEL-15570: camel-jte component
---
 bom/camel-bom/pom.xml                              |   5 +
 catalog/camel-allcomponents/pom.xml                |   5 +
 .../org/apache/camel/catalog/components.properties |   1 +
 .../org/apache/camel/catalog/components/jte.json   |  44 ++++++
 .../apache/camel/component/freemarker/example.ftl  |   1 +
 components/camel-jte/pom.xml                       |  69 ++++++++++
 .../component/jte/JteComponentConfigurer.java      |  79 +++++++++++
 .../camel/component/jte/JteEndpointConfigurer.java |  67 +++++++++
 .../camel/component/jte/JteEndpointUriFactory.java |  72 ++++++++++
 .../services/org/apache/camel/component.properties |   7 +
 .../services/org/apache/camel/component/jte        |   2 +
 .../org/apache/camel/configurer/jte-component      |   2 +
 .../org/apache/camel/configurer/jte-endpoint       |   2 +
 .../org/apache/camel/urifactory/jte-endpoint       |   2 +
 .../org/apache/camel/component/jte/jte.json        |  44 ++++++
 .../camel-jte/src/main/docs/jte-component.adoc     | 118 ++++++++++++++++
 .../camel/component/jte/JteCodeResolver.java       |  66 +++++++++
 .../apache/camel/component/jte/JteComponent.java   | 153 +++++++++++++++++++++
 .../apache/camel/component/jte/JteConstants.java   |  34 +++++
 .../apache/camel/component/jte/JteEndpoint.java    | 132 ++++++++++++++++++
 .../java/org/apache/camel/component/jte/Model.java |  65 +++++++++
 .../camel/component/jte/JteDataModelTest.java      |  63 +++++++++
 .../component/jte/JteTemplateFromHeaderTest.java   |  68 +++++++++
 .../org/apache/camel/component/jte/JteTest.java    |  63 +++++++++
 .../org/apache/camel/component/jte/MyModel.java    |  23 ++++
 .../camel-jte/src/test/resources/log4j2.properties |  28 ++++
 .../org/apache/camel/component/jte/custom.jte      |   4 +
 .../org/apache/camel/component/jte/example.jte     |   4 +
 .../org/apache/camel/main/components.properties    |   1 +
 .../camel-component-known-dependencies.properties  |   1 +
 parent/pom.xml                                     |   5 +
 pom.xml                                            |   1 +
 32 files changed, 1231 insertions(+)

diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml
index fd13cbcf4bd..5b8457b9a00 100644
--- a/bom/camel-bom/pom.xml
+++ b/bom/camel-bom/pom.xml
@@ -1222,6 +1222,11 @@
         <artifactId>camel-jta</artifactId>
         <version>${project.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-jte</artifactId>
+        <version>${project.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
         <artifactId>camel-kafka</artifactId>
diff --git a/catalog/camel-allcomponents/pom.xml b/catalog/camel-allcomponents/pom.xml
index c4f8be0e682..4d850ff6d17 100644
--- a/catalog/camel-allcomponents/pom.xml
+++ b/catalog/camel-allcomponents/pom.xml
@@ -1047,6 +1047,11 @@
             <artifactId>camel-jta</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-jte</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-kafka</artifactId>
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties
index a22ec489672..479b881f263 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties
@@ -179,6 +179,7 @@ json-patch
 json-validator
 jsonata
 jt400
+jte
 kafka
 kamelet
 knative
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jte.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jte.json
new file mode 100644
index 00000000000..200bea8807d
--- /dev/null
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jte.json
@@ -0,0 +1,44 @@
+{
+  "component": {
+    "kind": "component",
+    "name": "jte",
+    "title": "JTE",
+    "description": "Transform messages using JTE templates.",
+    "deprecated": false,
+    "firstVersion": "4.4.0",
+    "label": "transformation",
+    "javaType": "org.apache.camel.component.jte.JteComponent",
+    "supportLevel": "Preview",
+    "groupId": "org.apache.camel",
+    "artifactId": "camel-jte",
+    "version": "4.4.0-SNAPSHOT",
+    "scheme": "jte",
+    "extendsScheme": "",
+    "syntax": "jte:resourceUri",
+    "async": false,
+    "api": false,
+    "consumerOnly": false,
+    "producerOnly": true,
+    "lenientProperties": false
+  },
+  "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 [...]
+    "lazyStartProducer": { "index": 2, "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": 3, "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": 4, "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": 5, "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" },
+    "CamelJteTemplate": { "index": 1, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The template to use instead of the endpoint configured.", "constantName": "org.apache.camel.component.jte.JteConstants#JTE_TEMPLATE" },
+    "CamelJteDataModel": { "index": 2, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "Object", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The data model", "constantName": "org.apache.camel.component.jte.JteConstants#JTE_DATA_MODEL" }
+  },
+  "properties": {
+    "resourceUri": { "index": 0, "kind": "path", "displayName": "Resource Uri", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "supportFileReference": true, "description": "Path to the resource. You can prefix with: classpath, file, http, ref, or bean. classpath, file and http loads the resource using these protocols (classpath is default). ref will look [...]
+    "allowContextMapAll": { "index": 1, "kind": "parameter", "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 C [...]
+    "allowTemplateFromHeader": { "index": 2, "kind": "parameter", "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 s [...]
+    "contentCache": { "index": 3, "kind": "parameter", "displayName": "Content Cache", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Sets whether to use resource content cache or not" },
+    "lazyStartProducer": { "index": 4, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "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 produc [...]
+  }
+}
diff --git a/components/camel-freemarker/src/test/resources/org/apache/camel/component/freemarker/example.ftl b/components/camel-freemarker/src/test/resources/org/apache/camel/component/freemarker/example.ftl
index b7e6e721a68..4a575467956 100644
--- a/components/camel-freemarker/src/test/resources/org/apache/camel/component/freemarker/example.ftl
+++ b/components/camel-freemarker/src/test/resources/org/apache/camel/component/freemarker/example.ftl
@@ -12,6 +12,7 @@
     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.
 
diff --git a/components/camel-jte/pom.xml b/components/camel-jte/pom.xml
new file mode 100644
index 00000000000..34532bfc05d
--- /dev/null
+++ b/components/camel-jte/pom.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>components</artifactId>
+        <version>4.4.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>camel-jte</artifactId>
+    <packaging>jar</packaging>
+    <name>Camel :: JTA</name>
+    <description>Camel Java Template Engine support</description>
+
+    <properties>
+        <camel.surefire.parallel>true</camel.surefire.parallel>
+    </properties>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-support</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>gg.jte</groupId>
+            <artifactId>jte</artifactId>
+            <version>3.1.6</version>
+        </dependency>
+
+        <!-- testing -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test-junit5</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
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
new file mode 100644
index 00000000000..086841ac7d9
--- /dev/null
+++ b/components/camel-jte/src/generated/java/org/apache/camel/component/jte/JteComponentConfigurer.java
@@ -0,0 +1,79 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.component.jte;
+
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.ExtendedPropertyConfigurerGetter;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.spi.ConfigurerStrategy;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.support.component.PropertyConfigurerSupport;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@SuppressWarnings("unchecked")
+public class JteComponentConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter {
+
+    @Override
+    public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
+        JteComponent target = (JteComponent) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "allowcontextmapall":
+        case "allowContextMapAll": target.setAllowContextMapAll(property(camelContext, boolean.class, value)); return true;
+        case "allowtemplatefromheader":
+        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 "lazystartproducer":
+        case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true;
+        case "precompile":
+        case "preCompile": target.setPreCompile(property(camelContext, boolean.class, value)); return true;
+        case "workdir":
+        case "workDir": target.setWorkDir(property(camelContext, java.lang.String.class, value)); return true;
+        default: return false;
+        }
+    }
+
+    @Override
+    public Class<?> getOptionType(String name, boolean ignoreCase) {
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "allowcontextmapall":
+        case "allowContextMapAll": return boolean.class;
+        case "allowtemplatefromheader":
+        case "allowTemplateFromHeader": return boolean.class;
+        case "autowiredenabled":
+        case "autowiredEnabled": return boolean.class;
+        case "lazystartproducer":
+        case "lazyStartProducer": return boolean.class;
+        case "precompile":
+        case "preCompile": return boolean.class;
+        case "workdir":
+        case "workDir": return java.lang.String.class;
+        default: return null;
+        }
+    }
+
+    @Override
+    public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+        JteComponent target = (JteComponent) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "allowcontextmapall":
+        case "allowContextMapAll": return target.isAllowContextMapAll();
+        case "allowtemplatefromheader":
+        case "allowTemplateFromHeader": return target.isAllowTemplateFromHeader();
+        case "autowiredenabled":
+        case "autowiredEnabled": return target.isAutowiredEnabled();
+        case "lazystartproducer":
+        case "lazyStartProducer": return target.isLazyStartProducer();
+        case "precompile":
+        case "preCompile": return target.isPreCompile();
+        case "workdir":
+        case "workDir": return target.getWorkDir();
+        default: return null;
+        }
+    }
+}
+
diff --git a/components/camel-jte/src/generated/java/org/apache/camel/component/jte/JteEndpointConfigurer.java b/components/camel-jte/src/generated/java/org/apache/camel/component/jte/JteEndpointConfigurer.java
new file mode 100644
index 00000000000..41c35e2e338
--- /dev/null
+++ b/components/camel-jte/src/generated/java/org/apache/camel/component/jte/JteEndpointConfigurer.java
@@ -0,0 +1,67 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.component.jte;
+
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.ExtendedPropertyConfigurerGetter;
+import org.apache.camel.spi.PropertyConfigurerGetter;
+import org.apache.camel.spi.ConfigurerStrategy;
+import org.apache.camel.spi.GeneratedPropertyConfigurer;
+import org.apache.camel.util.CaseInsensitiveMap;
+import org.apache.camel.support.component.PropertyConfigurerSupport;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@SuppressWarnings("unchecked")
+public class JteEndpointConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter {
+
+    @Override
+    public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
+        JteEndpoint target = (JteEndpoint) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "allowcontextmapall":
+        case "allowContextMapAll": target.setAllowContextMapAll(property(camelContext, boolean.class, value)); return true;
+        case "allowtemplatefromheader":
+        case "allowTemplateFromHeader": target.setAllowTemplateFromHeader(property(camelContext, boolean.class, value)); return true;
+        case "contentcache":
+        case "contentCache": target.setContentCache(property(camelContext, boolean.class, value)); return true;
+        case "lazystartproducer":
+        case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true;
+        default: return false;
+        }
+    }
+
+    @Override
+    public Class<?> getOptionType(String name, boolean ignoreCase) {
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "allowcontextmapall":
+        case "allowContextMapAll": return boolean.class;
+        case "allowtemplatefromheader":
+        case "allowTemplateFromHeader": return boolean.class;
+        case "contentcache":
+        case "contentCache": return boolean.class;
+        case "lazystartproducer":
+        case "lazyStartProducer": return boolean.class;
+        default: return null;
+        }
+    }
+
+    @Override
+    public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
+        JteEndpoint target = (JteEndpoint) obj;
+        switch (ignoreCase ? name.toLowerCase() : name) {
+        case "allowcontextmapall":
+        case "allowContextMapAll": return target.isAllowContextMapAll();
+        case "allowtemplatefromheader":
+        case "allowTemplateFromHeader": return target.isAllowTemplateFromHeader();
+        case "contentcache":
+        case "contentCache": return target.isContentCache();
+        case "lazystartproducer":
+        case "lazyStartProducer": return target.isLazyStartProducer();
+        default: return null;
+        }
+    }
+}
+
diff --git a/components/camel-jte/src/generated/java/org/apache/camel/component/jte/JteEndpointUriFactory.java b/components/camel-jte/src/generated/java/org/apache/camel/component/jte/JteEndpointUriFactory.java
new file mode 100644
index 00000000000..149c064c8ff
--- /dev/null
+++ b/components/camel-jte/src/generated/java/org/apache/camel/component/jte/JteEndpointUriFactory.java
@@ -0,0 +1,72 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.component.jte;
+
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.camel.spi.EndpointUriFactory;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+public class JteEndpointUriFactory extends org.apache.camel.support.component.EndpointUriFactorySupport implements EndpointUriFactory {
+
+    private static final String BASE = ":resourceUri";
+
+    private static final Set<String> PROPERTY_NAMES;
+    private static final Set<String> SECRET_PROPERTY_NAMES;
+    private static final Set<String> MULTI_VALUE_PREFIXES;
+    static {
+        Set<String> props = new HashSet<>(5);
+        props.add("allowContextMapAll");
+        props.add("allowTemplateFromHeader");
+        props.add("contentCache");
+        props.add("lazyStartProducer");
+        props.add("resourceUri");
+        PROPERTY_NAMES = Collections.unmodifiableSet(props);
+        SECRET_PROPERTY_NAMES = Collections.emptySet();
+        MULTI_VALUE_PREFIXES = Collections.emptySet();
+    }
+
+    @Override
+    public boolean isEnabled(String scheme) {
+        return "jte".equals(scheme);
+    }
+
+    @Override
+    public String buildUri(String scheme, Map<String, Object> properties, boolean encode) throws URISyntaxException {
+        String syntax = scheme + BASE;
+        String uri = syntax;
+
+        Map<String, Object> copy = new HashMap<>(properties);
+
+        uri = buildPathParameter(syntax, uri, "resourceUri", null, true, copy);
+        uri = buildQueryParameters(uri, copy, encode);
+        return uri;
+    }
+
+    @Override
+    public Set<String> propertyNames() {
+        return PROPERTY_NAMES;
+    }
+
+    @Override
+    public Set<String> secretPropertyNames() {
+        return SECRET_PROPERTY_NAMES;
+    }
+
+    @Override
+    public Set<String> multiValuePrefixes() {
+        return MULTI_VALUE_PREFIXES;
+    }
+
+    @Override
+    public boolean isLenientProperties() {
+        return false;
+    }
+}
+
diff --git a/components/camel-jte/src/generated/resources/META-INF/services/org/apache/camel/component.properties b/components/camel-jte/src/generated/resources/META-INF/services/org/apache/camel/component.properties
new file mode 100644
index 00000000000..a9b6b47fdb8
--- /dev/null
+++ b/components/camel-jte/src/generated/resources/META-INF/services/org/apache/camel/component.properties
@@ -0,0 +1,7 @@
+# Generated by camel build tools - do NOT edit this file!
+components=jte
+groupId=org.apache.camel
+artifactId=camel-jte
+version=4.4.0-SNAPSHOT
+projectName=Camel :: JTA
+projectDescription=Camel Java Template Engine support
diff --git a/components/camel-jte/src/generated/resources/META-INF/services/org/apache/camel/component/jte b/components/camel-jte/src/generated/resources/META-INF/services/org/apache/camel/component/jte
new file mode 100644
index 00000000000..dd2d8be84f7
--- /dev/null
+++ b/components/camel-jte/src/generated/resources/META-INF/services/org/apache/camel/component/jte
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.jte.JteComponent
diff --git a/components/camel-jte/src/generated/resources/META-INF/services/org/apache/camel/configurer/jte-component b/components/camel-jte/src/generated/resources/META-INF/services/org/apache/camel/configurer/jte-component
new file mode 100644
index 00000000000..05a55ee592d
--- /dev/null
+++ b/components/camel-jte/src/generated/resources/META-INF/services/org/apache/camel/configurer/jte-component
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.jte.JteComponentConfigurer
diff --git a/components/camel-jte/src/generated/resources/META-INF/services/org/apache/camel/configurer/jte-endpoint b/components/camel-jte/src/generated/resources/META-INF/services/org/apache/camel/configurer/jte-endpoint
new file mode 100644
index 00000000000..53337ab884f
--- /dev/null
+++ b/components/camel-jte/src/generated/resources/META-INF/services/org/apache/camel/configurer/jte-endpoint
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.jte.JteEndpointConfigurer
diff --git a/components/camel-jte/src/generated/resources/META-INF/services/org/apache/camel/urifactory/jte-endpoint b/components/camel-jte/src/generated/resources/META-INF/services/org/apache/camel/urifactory/jte-endpoint
new file mode 100644
index 00000000000..7512fe65551
--- /dev/null
+++ b/components/camel-jte/src/generated/resources/META-INF/services/org/apache/camel/urifactory/jte-endpoint
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+class=org.apache.camel.component.jte.JteEndpointUriFactory
diff --git a/components/camel-jte/src/generated/resources/org/apache/camel/component/jte/jte.json b/components/camel-jte/src/generated/resources/org/apache/camel/component/jte/jte.json
new file mode 100644
index 00000000000..200bea8807d
--- /dev/null
+++ b/components/camel-jte/src/generated/resources/org/apache/camel/component/jte/jte.json
@@ -0,0 +1,44 @@
+{
+  "component": {
+    "kind": "component",
+    "name": "jte",
+    "title": "JTE",
+    "description": "Transform messages using JTE templates.",
+    "deprecated": false,
+    "firstVersion": "4.4.0",
+    "label": "transformation",
+    "javaType": "org.apache.camel.component.jte.JteComponent",
+    "supportLevel": "Preview",
+    "groupId": "org.apache.camel",
+    "artifactId": "camel-jte",
+    "version": "4.4.0-SNAPSHOT",
+    "scheme": "jte",
+    "extendsScheme": "",
+    "syntax": "jte:resourceUri",
+    "async": false,
+    "api": false,
+    "consumerOnly": false,
+    "producerOnly": true,
+    "lenientProperties": false
+  },
+  "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 [...]
+    "lazyStartProducer": { "index": 2, "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": 3, "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": 4, "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": 5, "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" },
+    "CamelJteTemplate": { "index": 1, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The template to use instead of the endpoint configured.", "constantName": "org.apache.camel.component.jte.JteConstants#JTE_TEMPLATE" },
+    "CamelJteDataModel": { "index": 2, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "Object", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The data model", "constantName": "org.apache.camel.component.jte.JteConstants#JTE_DATA_MODEL" }
+  },
+  "properties": {
+    "resourceUri": { "index": 0, "kind": "path", "displayName": "Resource Uri", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "supportFileReference": true, "description": "Path to the resource. You can prefix with: classpath, file, http, ref, or bean. classpath, file and http loads the resource using these protocols (classpath is default). ref will look [...]
+    "allowContextMapAll": { "index": 1, "kind": "parameter", "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 C [...]
+    "allowTemplateFromHeader": { "index": 2, "kind": "parameter", "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 s [...]
+    "contentCache": { "index": 3, "kind": "parameter", "displayName": "Content Cache", "group": "producer", "label": "", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Sets whether to use resource content cache or not" },
+    "lazyStartProducer": { "index": 4, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "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 produc [...]
+  }
+}
diff --git a/components/camel-jte/src/main/docs/jte-component.adoc b/components/camel-jte/src/main/docs/jte-component.adoc
new file mode 100644
index 00000000000..fceec0f6a33
--- /dev/null
+++ b/components/camel-jte/src/main/docs/jte-component.adoc
@@ -0,0 +1,118 @@
+= JTE Component
+:doctitle: JTE
+:shortname: jte
+:artifactid: camel-jte
+:description: Transform messages using JTE templates.
+:since: 4.4
+:supportlevel: Preview
+:tabs-sync-option:
+:component-header: Only producer is supported
+//Manually maintained attributes
+:camel-spring-boot-name: jte
+
+*Since Camel {since}*
+
+*{component-header}*
+
+The *jte:* component allows for processing a message using a
+https://jte.gg/[JTE] template. This can be ideal when
+using Templating to generate responses for
+requests.
+
+Maven users will need to add the following dependency to their `pom.xml`
+for this component:
+
+[source,xml]
+-------------------------------------------------------------------------------------
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-jte</artifactId>
+    <version>x.x.x</version> <!-- use the same version as your Camel core version -->
+</dependency>
+-------------------------------------------------------------------------------------
+
+== URI format
+
+---------------------------------
+jte:templateName[?options]
+---------------------------------
+
+Where *templateName* is the classpath-local URI of the template to
+invoke; or the complete URL of the remote template (eg:
+`\file://folder/myfile.jte`).
+
+
+// component-configure options: START
+
+// component-configure options: END
+
+// component options: START
+include::partial$component-configure-options.adoc[]
+include::partial$component-endpoint-options.adoc[]
+// component options: END
+
+// endpoint options: START
+
+// endpoint options: END
+
+
+== JTE Context
+
+Camel will provide exchange information in the JTE context, as a `org.apache.camel.component.jte.Model` class
+with the following information:
+
+[width="100%",cols="50%,50%",options="header",]
+|=======================================================================
+|key |value
+
+|`exchange` |The `Exchange` itself (only if allowContextMapAll=true).
+
+|`headers` |The headers of the message as `java.util.Map`.
+
+|`body` |The message body as `Object`.
+
+|`strBody()` | The message body converted to a String
+
+| `header("key")` | Message header with the given key converted to a String value.
+
+| `exchangeProperty("key")` | Exchange property with the given key converted to a String value (only if allowContextMapAll=true).
+
+|=======================================================================
+
+You can setup your custom JTE data model in the
+message header with the key "*CamelJteDataModel*" just like this
+
+
+== Dynamic templates
+
+Camel provides two headers by which you can define a different resource
+location for a template or the template content itself. If any of these
+headers is set then Camel uses this over the endpoint configured
+resource. This allows you to provide a dynamic template at runtime.
+
+// component headers: START
+include::partial$component-endpoint-headers.adoc[]
+// component headers: END
+
+== Samples
+
+For example you could use something like:
+
+[source,java]
+-------------------------------------------
+from("rest:get:item/{id}").
+  to("jte:com/acme/response.jte");
+-------------------------------------------
+
+To use a JTE template to formulate a response to the REST get call.
+
+[source,java]
+----
+@import org.apache.camel.component.jte.Model
+@param Model model
+
+The item ${model.header("id")} is being processed.
+----
+
+
+include::spring-boot:partial$starter.adoc[]
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
new file mode 100644
index 00000000000..0345c6c25e6
--- /dev/null
+++ b/components/camel-jte/src/main/java/org/apache/camel/component/jte/JteCodeResolver.java
@@ -0,0 +1,66 @@
+/*
+ * 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 java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import gg.jte.CodeResolver;
+import org.apache.camel.CamelContext;
+import org.apache.camel.util.IOHelper;
+
+/**
+ * To load JTE templates from classpath
+ */
+public class JteCodeResolver implements CodeResolver {
+
+    private final CamelContext camelContext;
+    private final Map<String, String> headerTemplates = new ConcurrentHashMap<>();
+
+    public JteCodeResolver(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
+    public void addTemplateFromHeader(String exchangeId, String template) {
+        if (exchangeId != null && template != null) {
+            headerTemplates.put(exchangeId, template);
+        }
+    }
+
+    @Override
+    public String resolve(String name) {
+        String answer = headerTemplates.remove(name);
+        if (answer == null) {
+            InputStream is = camelContext.getClassResolver().loadResourceAsStream(name);
+            if (is != null) {
+                try {
+                    answer = IOHelper.loadText(is);
+                } catch (IOException e) {
+                    // ignore
+                }
+            }
+        }
+        return answer;
+    }
+
+    @Override
+    public long getLastModified(String name) {
+        return 0;
+    }
+}
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
new file mode 100644
index 00000000000..3b2060698e2
--- /dev/null
+++ b/components/camel-jte/src/main/java/org/apache/camel/component/jte/JteComponent.java
@@ -0,0 +1,153 @@
+/*
+ * 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 java.nio.file.Path;
+import java.util.Map;
+
+import gg.jte.ContentType;
+import gg.jte.TemplateEngine;
+import org.apache.camel.Endpoint;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.annotations.Component;
+import org.apache.camel.support.DefaultComponent;
+import org.apache.camel.support.ResourceHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component("jte")
+public class JteComponent extends DefaultComponent {
+
+    private static final Logger LOG = LoggerFactory.getLogger(JteComponent.class);
+
+    private JteCodeResolver codeResolver;
+    private TemplateEngine templateEngine;
+
+    @Metadata(defaultValue = "jte-classes")
+    private String workDir = "jte-classes";
+    @Metadata
+    private boolean preCompile;
+    @Metadata(defaultValue = "Plain")
+    private ContentType contentType = ContentType.Plain;
+    @Metadata
+    private boolean allowTemplateFromHeader;
+    @Metadata
+    private boolean allowContextMapAll;
+
+    @Override
+    protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
+        JteEndpoint endpoint = new JteEndpoint(uri, this, remaining);
+        endpoint.setAllowTemplateFromHeader(allowTemplateFromHeader);
+        endpoint.setAllowContextMapAll(allowContextMapAll);
+
+        setProperties(endpoint, parameters);
+
+        // if its a http resource then append any remaining parameters and update the resource uri
+        if (ResourceHelper.isHttpUri(remaining)) {
+            remaining = ResourceHelper.appendParameters(remaining, parameters);
+            endpoint.setResourceUri(remaining);
+        }
+
+        return endpoint;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+
+        Path dir = Path.of(workDir);
+        if (preCompile) {
+            LOG.info("Using pre-compiling JTE templates: {}", workDir);
+            templateEngine
+                    = TemplateEngine.createPrecompiled(dir, contentType, getCamelContext().getApplicationContextClassLoader());
+        } else {
+            LOG.info("Using runtime compiled JTE templates: {}", workDir);
+            codeResolver = new JteCodeResolver(getCamelContext());
+            templateEngine = TemplateEngine.create(codeResolver, dir, contentType,
+                    getCamelContext().getApplicationContextClassLoader());
+        }
+    }
+
+    @Override
+    protected void doShutdown() throws Exception {
+        super.doShutdown();
+
+        if (templateEngine != null) {
+            templateEngine.cleanAll();
+        }
+    }
+
+    public TemplateEngine getTemplateEngine() {
+        return templateEngine;
+    }
+
+    public JteCodeResolver getCodeResolver() {
+        return codeResolver;
+    }
+
+    public String getWorkDir() {
+        return workDir;
+    }
+
+    /**
+     * Work directory where JTE will store compiled templates.
+     */
+    public void setWorkDir(String workDir) {
+        this.workDir = workDir;
+    }
+
+    public boolean isPreCompile() {
+        return preCompile;
+    }
+
+    /**
+     * 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 compiling
+     * it.
+     */
+    public void setPreCompile(boolean preCompile) {
+        this.preCompile = preCompile;
+    }
+
+    public boolean isAllowTemplateFromHeader() {
+        return allowTemplateFromHeader;
+    }
+
+    /**
+     * 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
+     * security vulnerability if the header is coming from a malicious user, so use this with care.
+     */
+    public void setAllowTemplateFromHeader(boolean allowTemplateFromHeader) {
+        this.allowTemplateFromHeader = allowTemplateFromHeader;
+    }
+
+    public boolean isAllowContextMapAll() {
+        return allowContextMapAll;
+    }
+
+    /**
+     * 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 CamelContext. Doing so impose
+     * a potential security risk as this opens access to the full power of CamelContext API.
+     */
+    public void setAllowContextMapAll(boolean allowContextMapAll) {
+        this.allowContextMapAll = allowContextMapAll;
+    }
+
+}
diff --git a/components/camel-jte/src/main/java/org/apache/camel/component/jte/JteConstants.java b/components/camel-jte/src/main/java/org/apache/camel/component/jte/JteConstants.java
new file mode 100644
index 00000000000..f95e6c56ddb
--- /dev/null
+++ b/components/camel-jte/src/main/java/org/apache/camel/component/jte/JteConstants.java
@@ -0,0 +1,34 @@
+/*
+ * 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.spi.Metadata;
+
+public class JteConstants {
+
+    @Metadata(description = "A URI for the template resource to use instead of the endpoint configured.", javaType = "String")
+    public static final String JTE_RESOURCE_URI = "CamelJteResourceUri";
+    @Metadata(description = "The template to use instead of the endpoint configured.", javaType = "String")
+    public static final String JTE_TEMPLATE = "CamelJteTemplate";
+    @Metadata(description = "The data model", javaType = "Object")
+    public static final String JTE_DATA_MODEL = "CamelJteDataModel";
+
+    private JteConstants() {
+        // Utility class
+    }
+
+}
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
new file mode 100644
index 00000000000..05ae42b4a68
--- /dev/null
+++ b/components/camel-jte/src/main/java/org/apache/camel/component/jte/JteEndpoint.java
@@ -0,0 +1,132 @@
+/*
+ * 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 gg.jte.TemplateEngine;
+import gg.jte.TemplateOutput;
+import gg.jte.output.StringOutput;
+import org.apache.camel.Category;
+import org.apache.camel.Component;
+import org.apache.camel.Exchange;
+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.util.ObjectHelper;
+
+/**
+ * Transform messages using JTE templates.
+ */
+@UriEndpoint(firstVersion = "4.4.0", scheme = "jte", title = "JTE", syntax = "jte:resourceUri",
+             producerOnly = true, category = { Category.TRANSFORMATION }, headersClass = JteConstants.class)
+public class JteEndpoint extends ResourceEndpoint {
+
+    @UriParam(defaultValue = "false")
+    private boolean allowTemplateFromHeader;
+
+    public JteEndpoint() {
+    }
+
+    public JteEndpoint(String endpointUri, Component component, String resourceUri) {
+        super(endpointUri, component, resourceUri);
+    }
+
+    @Override
+    public JteComponent getComponent() {
+        return (JteComponent) super.getComponent();
+    }
+
+    public boolean isAllowTemplateFromHeader() {
+        return allowTemplateFromHeader;
+    }
+
+    /**
+     * 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
+     * security vulnerability if the header is coming from a malicious user, so use this with care.
+     */
+    public void setAllowTemplateFromHeader(boolean allowTemplateFromHeader) {
+        this.allowTemplateFromHeader = allowTemplateFromHeader;
+    }
+
+    public JteEndpoint findOrCreateEndpoint(String uri, String newResourceUri) {
+        String newUri = uri.replace(getResourceUri(), newResourceUri);
+        log.debug("Getting endpoint with URI: {}", newUri);
+        return getCamelContext().getEndpoint(newUri, JteEndpoint.class);
+    }
+
+    @Override
+    protected void onExchange(Exchange exchange) throws Exception {
+        String path = getResourceUri();
+        ObjectHelper.notNull(path, "resourceUri");
+
+        if (allowTemplateFromHeader) {
+            String newResourceUri = exchange.getIn().getHeader(JteConstants.JTE_RESOURCE_URI, String.class);
+            if (newResourceUri != null) {
+                exchange.getIn().removeHeader(JteConstants.JTE_RESOURCE_URI);
+                log.debug("{} set to {} creating new endpoint to handle exchange", JteConstants.JTE_RESOURCE_URI,
+                        newResourceUri);
+                JteEndpoint newEndpoint = findOrCreateEndpoint(getEndpointUri(), newResourceUri);
+                newEndpoint.onExchange(exchange);
+                return;
+            }
+        }
+
+        String name = getResourceUri();
+        String content;
+        if (allowTemplateFromHeader) {
+            content = exchange.getIn().getHeader(JteConstants.JTE_TEMPLATE, String.class);
+            if (content != null) {
+                // 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);
+                }
+            }
+        }
+        Object dataModel = null;
+        if (allowTemplateFromHeader) {
+            dataModel = exchange.getIn().getHeader(JteConstants.JTE_DATA_MODEL, Object.class);
+        }
+        if (dataModel == null) {
+            Model model = new Model(getCamelContext());
+            model.body = exchange.getMessage().getBody();
+            model.headers = exchange.getMessage().getHeaders();
+            if (isAllowContextMapAll()) {
+                model.exchange = exchange;
+            }
+            dataModel = model;
+        }
+
+        // let JTE parse and generate the result in buffer
+        TemplateEngine template = getComponent().getTemplateEngine();
+
+        TemplateOutput buffer = new StringOutput();
+        template.render(name, dataModel, buffer);
+
+        // now lets store the result
+        String s = buffer.toString();
+        // trim leading and ending empty lines
+        s = s.trim();
+        ExchangeHelper.setInOutBodyPatternAware(exchange, s);
+    }
+
+}
diff --git a/components/camel-jte/src/main/java/org/apache/camel/component/jte/Model.java b/components/camel-jte/src/main/java/org/apache/camel/component/jte/Model.java
new file mode 100644
index 00000000000..8a2cdbeea92
--- /dev/null
+++ b/components/camel-jte/src/main/java/org/apache/camel/component/jte/Model.java
@@ -0,0 +1,65 @@
+/*
+ * 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 java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+
+/**
+ * Data model for JTE templates.
+ */
+public final class Model {
+
+    private final CamelContext camelContext;
+
+    public Model(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
+    public Exchange exchange;
+    public Map<String, Object> headers;
+    public Object body;
+
+    public String header(String key) {
+        Object val = headers.get(key);
+        if (val != null) {
+            return camelContext.getTypeConverter().convertTo(String.class, exchange, val);
+        }
+        return null;
+    }
+
+    public String exchangeProperty(String key) {
+        if (exchange != null) {
+            Object val = exchange.getProperty(key);
+            if (val != null) {
+                return camelContext.getTypeConverter().convertTo(String.class, exchange, val);
+            }
+        }
+        return null;
+    }
+
+    public String strBody() {
+        Object val = body;
+        if (val != null) {
+            return camelContext.getTypeConverter().convertTo(String.class, exchange, val);
+        }
+        return null;
+    }
+
+}
diff --git a/components/camel-jte/src/test/java/org/apache/camel/component/jte/JteDataModelTest.java b/components/camel-jte/src/test/java/org/apache/camel/component/jte/JteDataModelTest.java
new file mode 100644
index 00000000000..5f4426f613e
--- /dev/null
+++ b/components/camel-jte/src/test/java/org/apache/camel/component/jte/JteDataModelTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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 org.junit.jupiter.api.parallel.Isolated;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@Isolated
+public class JteDataModelTest extends CamelTestSupport {
+
+    @Test
+    public void testJteDataModel() throws Exception {
+        Exchange exchange = template.request("direct:a", new Processor() {
+            @Override
+            public void process(Exchange exchange) {
+                MyModel myModel = new MyModel();
+                myModel.foo = "Jack";
+                myModel.age = 44;
+                exchange.getIn().setHeader(JteConstants.JTE_DATA_MODEL, myModel);
+            }
+        });
+        if (exchange.isFailed()) {
+            throw exchange.getException();
+        }
+
+        assertEquals("Hello Jack you are 44 years old", exchange.getMessage().getBody());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                JteComponent jte = context.getComponent("jte", JteComponent.class);
+                jte.setWorkDir("target/jte-classes");
+
+                // START SNIPPET: example
+                from("direct:a").to(
+                        "jte:org/apache/camel/component/jte/custom.jte?allowTemplateFromHeader=true");
+                // END SNIPPET: example
+            }
+        };
+    }
+}
diff --git a/components/camel-jte/src/test/java/org/apache/camel/component/jte/JteTemplateFromHeaderTest.java b/components/camel-jte/src/test/java/org/apache/camel/component/jte/JteTemplateFromHeaderTest.java
new file mode 100644
index 00000000000..8f089815d78
--- /dev/null
+++ b/components/camel-jte/src/test/java/org/apache/camel/component/jte/JteTemplateFromHeaderTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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 org.junit.jupiter.api.parallel.Isolated;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@Isolated
+public class JteTemplateFromHeaderTest extends CamelTestSupport {
+
+    private final String tmp = """
+            @import org.apache.camel.component.jte.Model
+            @param Model model
+
+            Hello ${model.header("name")}.
+                            """;
+
+    @Test
+    public void testHeader() throws Exception {
+        Exchange exchange = template.request("direct:a", new Processor() {
+            @Override
+            public void process(Exchange exchange) {
+                exchange.getIn().setHeader(JteConstants.JTE_TEMPLATE, tmp);
+                exchange.getIn().setHeader("name", "Scott");
+            }
+        });
+        if (exchange.isFailed()) {
+            throw exchange.getException();
+        }
+
+        assertEquals("Hello Scott.", exchange.getMessage().getBody());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                JteComponent jte = context.getComponent("jte", JteComponent.class);
+                jte.setWorkDir("target/jte-classes");
+
+                // START SNIPPET: example
+                from("direct:a").to(
+                        "jte:org/apache/camel/component/jte/dummy.jte?allowTemplateFromHeader=true");
+                // END SNIPPET: example
+            }
+        };
+    }
+}
diff --git a/components/camel-jte/src/test/java/org/apache/camel/component/jte/JteTest.java b/components/camel-jte/src/test/java/org/apache/camel/component/jte/JteTest.java
new file mode 100644
index 00000000000..70e038a6cb2
--- /dev/null
+++ b/components/camel-jte/src/test/java/org/apache/camel/component/jte/JteTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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 org.junit.jupiter.api.parallel.Isolated;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@Isolated
+public class JteTest extends CamelTestSupport {
+
+    @Test
+    public void testJteLetter() throws Exception {
+        Exchange exchange = template.request("direct:a", new Processor() {
+            @Override
+            public void process(Exchange exchange) {
+                exchange.getIn().setBody("Monday");
+                exchange.getIn().setHeader("name", "Christian");
+                exchange.setProperty("item", "7");
+            }
+        });
+        if (exchange.isFailed()) {
+            throw exchange.getException();
+        }
+
+        assertEquals("Dear Christian. You ordered item 7 on Monday.", exchange.getMessage().getBody());
+        assertEquals("Christian", exchange.getMessage().getHeader("name"));
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                JteComponent jte = context.getComponent("jte", JteComponent.class);
+                jte.setWorkDir("target/jte-classes");
+
+                // START SNIPPET: example
+                from("direct:a").to(
+                        "jte:org/apache/camel/component/jte/example.jte?allowContextMapAll=true");
+                // END SNIPPET: example
+            }
+        };
+    }
+}
diff --git a/components/camel-jte/src/test/java/org/apache/camel/component/jte/MyModel.java b/components/camel-jte/src/test/java/org/apache/camel/component/jte/MyModel.java
new file mode 100644
index 00000000000..d6fee5faaa7
--- /dev/null
+++ b/components/camel-jte/src/test/java/org/apache/camel/component/jte/MyModel.java
@@ -0,0 +1,23 @@
+/*
+ * 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;
+
+public class MyModel {
+
+    public String foo;
+    public int age;
+}
diff --git a/components/camel-jte/src/test/resources/log4j2.properties b/components/camel-jte/src/test/resources/log4j2.properties
new file mode 100644
index 00000000000..754358115de
--- /dev/null
+++ b/components/camel-jte/src/test/resources/log4j2.properties
@@ -0,0 +1,28 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+appender.out.type = File
+appender.out.name = out
+appender.out.fileName = target/camel-jte-test.log
+appender.out.layout.type = PatternLayout
+appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+appender.stdout.type = Console
+appender.stdout.name = stdout
+appender.stdout.layout.type = PatternLayout
+appender.stdout.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+rootLogger.level = INFO
+rootLogger.appenderRef.out.ref = out
diff --git a/components/camel-jte/src/test/resources/org/apache/camel/component/jte/custom.jte b/components/camel-jte/src/test/resources/org/apache/camel/component/jte/custom.jte
new file mode 100644
index 00000000000..efcec258593
--- /dev/null
+++ b/components/camel-jte/src/test/resources/org/apache/camel/component/jte/custom.jte
@@ -0,0 +1,4 @@
+@import org.apache.camel.component.jte.MyModel
+@param MyModel model
+
+Hello ${model.foo} you are ${model.age} years old
\ No newline at end of file
diff --git a/components/camel-jte/src/test/resources/org/apache/camel/component/jte/example.jte b/components/camel-jte/src/test/resources/org/apache/camel/component/jte/example.jte
new file mode 100644
index 00000000000..066b1692943
--- /dev/null
+++ b/components/camel-jte/src/test/resources/org/apache/camel/component/jte/example.jte
@@ -0,0 +1,4 @@
+@import org.apache.camel.component.jte.Model
+@param Model model
+
+Dear ${model.header("name")}. You ordered item ${model.exchangeProperty("item")} on ${model.strBody()}.
\ No newline at end of file
diff --git a/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties b/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties
index a22ec489672..479b881f263 100644
--- a/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties
+++ b/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties
@@ -179,6 +179,7 @@ json-patch
 json-validator
 jsonata
 jt400
+jte
 kafka
 kamelet
 knative
diff --git a/dsl/camel-kamelet-main/src/generated/resources/camel-component-known-dependencies.properties b/dsl/camel-kamelet-main/src/generated/resources/camel-component-known-dependencies.properties
index b5a3273f2fe..104f8d33a8b 100644
--- a/dsl/camel-kamelet-main/src/generated/resources/camel-component-known-dependencies.properties
+++ b/dsl/camel-kamelet-main/src/generated/resources/camel-component-known-dependencies.properties
@@ -191,6 +191,7 @@ org.apache.camel.component.jsonata.JsonataComponent=camel:jsonata
 org.apache.camel.component.jsonpatch.JsonPatchComponent=camel:json-patch
 org.apache.camel.component.jsonvalidator.JsonValidatorComponent=camel:json-validator
 org.apache.camel.component.jt400.Jt400Component=camel:jt400
+org.apache.camel.component.jte.JteComponent=camel:jte
 org.apache.camel.component.kafka.KafkaComponent=camel:kafka
 org.apache.camel.component.kamelet.KameletComponent=camel:kamelet
 org.apache.camel.component.knative.KnativeComponent=camel:knative
diff --git a/parent/pom.xml b/parent/pom.xml
index 0fa0dbaebfd..07fb55c6d1e 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -1644,6 +1644,11 @@
                 <artifactId>camel-jta</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.camel</groupId>
+                <artifactId>camel-jte</artifactId>
+                <version>${project.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.camel</groupId>
                 <artifactId>camel-kafka</artifactId>
diff --git a/pom.xml b/pom.xml
index 634f8e19aeb..95f444c5257 100644
--- a/pom.xml
+++ b/pom.xml
@@ -280,6 +280,7 @@
                                     <exclude>**/*utf16.vm</exclude>
                                     <exclude>**/.eslint*</exclude>
                                     <exclude>**/.pnp*</exclude>
+                                    <exclude>**/*.jte</exclude>
                                     <exclude>**/.yarn/**</exclude>
                                     <exclude>**/.yarnrc.yml</exclude>
                                     <exclude>**/CamelJBang.java</exclude>