You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by cd...@apache.org on 2023/07/04 11:56:48 UTC
[camel] 01/03: CAMEL-18698 Add support for multiple input/output data types on components
This is an automated email from the ASF dual-hosted git repository.
cdeppisch pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
commit 55191eca46a46ced9f73eb82751a5eca7d599f14
Author: Christoph Deppisch <cd...@redhat.com>
AuthorDate: Wed Jun 28 08:54:44 2023 +0200
CAMEL-18698 Add support for multiple input/output data types on components
- Add data type to transform EIP resulting in a transformation from given type to target type using a matching transformer implementation
- Enhance data type transformer resolving mechanism as follows:
- Add lazy loading of transformer implementations via resource path factory finder
- Add annotation based transformer loader (adds possibility to load transformer implementations with classpath scan)
- Add possibility to configure preloading of default Camel transformer implementations
- Add default Camel transformer implementations for String and byte[]
- Add CloudEvents transformer implementation to transform any Camel Exchange into CloudEvent Http or Json binding
- Add AWS S3 CloudEvents transformer implementation to transform getObject response into proper CloudEvent
---
.../org/apache/camel/catalog/models/transform.json | 8 +-
.../apache/camel/catalog/models/transformers.json | 2 +-
.../apache/camel/catalog/schemas/camel-spring.xsd | 29 +++
components/camel-aws/camel-aws2-s3/pom.xml | 8 +
.../AWS2S3CloudEventDataTypeTransformer.java | 54 ++++++
.../transformer/aws2-s3-application-cloudevents | 18 ++
.../AWS2S3CloudEventDataTypeTransformerTest.java | 69 +++++++
.../transform/AWS2S3TransformCloudEventsTest.java | 82 +++++++++
components/camel-cloudevents/pom.xml | 7 +
.../camel/component/cloudevents/CloudEvent.java | 16 ++
.../CloudEventHttpDataTypeTransformer.java | 69 +++++++
.../CloudEventJsonDataTypeTransformer.java | 88 +++++++++
.../transformer/application-cloudevents-json | 18 ++
.../transformer/http-application-cloudevents | 18 ++
.../CloudEventHttpDataTypeTransformerTest.java | 110 ++++++++++++
.../CloudEventJsonDataTypeTransformerTest.java | 103 +++++++++++
.../transformer/SpringTransformerRouteTest.xml | 18 +-
.../main/java/org/apache/camel/CamelContext.java | 14 +-
.../main/java/org/apache/camel/spi/DataType.java | 57 ++++--
.../org/apache/camel/spi/DataTypeTransformer.java | 60 +++++++
.../java/org/apache/camel/spi/Transformer.java | 62 ++++++-
.../org/apache/camel/spi/TransformerLoader.java} | 20 ++-
.../org/apache/camel/spi/TransformerResolver.java | 54 ++++++
.../camel/impl/engine/AbstractCamelContext.java | 4 +-
.../impl/engine/DefaultTransformerRegistry.java | 121 +++++++++++--
.../impl/engine/DefaultTransformerResolver.java | 65 +++++++
.../impl/engine/DefaultValidatorRegistry.java | 2 +-
.../apache/camel/impl/engine/TransformerKey.java | 46 +++--
.../org/apache/camel/impl/DefaultCamelContext.java | 12 +-
.../org/apache/camel/model/transform.json | 8 +-
.../org/apache/camel/model/transformer/jaxb.index | 1 +
.../camel/model/transformer/transformers.json | 2 +-
.../apache/camel/builder/TransformerBuilder.java | 55 +++++-
.../apache/camel/model/ProcessorDefinition.java | 28 +++
.../apache/camel/model/TransformDefinition.java | 50 ++++++
.../transformer/LoadTransformerDefinition.java | 64 +++++++
.../model/transformer/TransformerDefinition.java | 31 +++-
.../model/transformer/TransformersDefinition.java | 1 +
.../org/apache/camel/processor/ContractAdvice.java | 45 +++--
.../transformer/AnnotationTransformerLoader.java | 198 +++++++++++++++++++++
.../transformer/ByteArrayDataTypeTransformer.java} | 31 ++--
.../transformer/DataFormatTransformer.java | 16 +-
.../processor/transformer/DataTypeProcessor.java | 120 +++++++++++++
.../transformer/DefaultTransformerLoader.java | 48 +++++
.../transformer/ProcessorTransformer.java | 7 +-
.../transformer/StringDataTypeTransformer.java | 46 +++++
.../transformer/TypeConverterTransformer.java | 80 +++++++++
.../datatype/transformer/application-octet-stream | 18 ++
.../apache/camel/datatype/transformer/plain-text | 18 ++
.../org/apache/camel/reifier/TransformReifier.java | 10 ++
.../transformer/CustomTransformerReifier.java | 5 +-
.../transformer/DataFormatTransformerReifier.java | 3 +-
.../transformer/EndpointTransformerReifier.java | 2 +-
...merReifier.java => LoadTransformerReifier.java} | 25 +--
.../reifier/transformer/TransformerReifier.java | 3 +
.../core/xml/AbstractCamelContextFactoryBean.java | 12 +-
.../camel/builder/TransformerBuilderTest.java | 2 +-
.../engine/DefaultTransformerRegistryTest.java | 47 +++++
.../engine/DefaultTransformerResolverTest.java | 75 ++++++++
.../impl/engine/LowercaseDataTypeTransformer.java} | 19 +-
.../impl/engine/UppercaseDataTypeTransformer.java} | 19 +-
.../processor/TransformDataTypeProcessorTest.java | 45 +++++
.../ByteArrayDataTypeTransformerTest.java | 101 +++++++++++
.../transformer/DataTypeProcessorTest.java | 79 ++++++++
.../transformer/StringDataTypeTransformerTest.java | 89 +++++++++
.../transformer/TransformerRouteTest.java | 19 +-
.../custom/CustomDataTypeTransformer.java} | 19 +-
.../org/apache/camel/datatype/transformer/foo-json | 18 ++
.../apache/camel/datatype/transformer/lowercase | 18 ++
.../apache/camel/datatype/transformer/uppercase | 18 ++
.../api/management/mbean/CamelOpenMBeanTypes.java | 6 +-
.../management/mbean/ManagedTransformMBean.java | 6 +
.../DefaultManagementObjectStrategy.java | 5 +-
.../camel/management/mbean/ManagedTransformer.java | 16 +-
.../mbean/ManagedTransformerRegistry.java | 10 +-
.../management/ManagedTransformerRegistryTest.java | 16 +-
.../java/org/apache/camel/xml/in/ModelParser.java | 22 ++-
.../java/org/apache/camel/xml/out/ModelWriter.java | 14 ++
.../org/apache/camel/yaml/out/ModelWriter.java | 14 ++
.../dsl/yaml/deserializers/ModelDeserializers.java | 110 +++++++++++-
.../deserializers/ModelDeserializersResolver.java | 1 +
.../generated/resources/schema/camel-yaml-dsl.json | 47 +++++
.../generated/resources/schema/camelYamlDsl.json | 47 +++++
83 files changed, 2831 insertions(+), 212 deletions(-)
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/transform.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/transform.json
index 5e37dc5dd65..85e827be37f 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/transform.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/transform.json
@@ -13,8 +13,10 @@
},
"properties": {
"expression": { "index": 0, "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "js", "jsonpath", "language", "method", "mvel", "ognl", "python", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": fa [...]
- "disabled": { "index": 1, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
- "id": { "index": 2, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
- "description": { "index": 3, "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" }
+ "fromType": { "index": 1, "kind": "attribute", "displayName": "From Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "From type used in data type transformation." },
+ "toType": { "index": 2, "kind": "attribute", "displayName": "To Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "To type used as a target data type in the transformation." },
+ "disabled": { "index": 3, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
+ "id": { "index": 4, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
+ "description": { "index": 5, "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" }
}
}
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/transformers.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/transformers.json
index af5d7902054..1f2ae2ab00a 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/transformers.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/transformers.json
@@ -12,6 +12,6 @@
"output": false
},
"properties": {
- "transformers": { "index": 0, "kind": "element", "displayName": "Transformers", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.transformer.TransformerDefinition>", "oneOf": [ "customTransformer", "dataFormatTransformer", "endpointTransformer" ], "deprecated": false, "autowired": false, "secret": false, "description": "The configured transformers" }
+ "transformers": { "index": 0, "kind": "element", "displayName": "Transformers", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.transformer.TransformerDefinition>", "oneOf": [ "customTransformer", "dataFormatTransformer", "endpointTransformer", "loadTransformer" ], "deprecated": false, "autowired": false, "secret": false, "description": "The configured transformers" }
}
}
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
index 649a953edab..dc428d9a181 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd
@@ -13262,6 +13262,24 @@ Sets a reference to use for lookup the policy in the registry.
<xs:element ref="tns:xpath"/>
<xs:element ref="tns:xquery"/>
</xs:choice>
+ <xs:attribute name="fromType" type="xs:string">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+<![CDATA[
+From type used in data type transformation.
+]]>
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="toType" type="xs:string">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+<![CDATA[
+To type used as a target data type in the transformation.
+]]>
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:extension>
</xs:complexContent>
</xs:complexType>
@@ -16165,6 +16183,7 @@ Sets the component name that this definition will apply to.
<xs:complexType abstract="true" name="transformer">
<xs:sequence/>
<xs:attribute name="scheme" type="xs:string"/>
+ <xs:attribute name="name" type="xs:string"/>
<xs:attribute name="fromType" type="xs:string"/>
<xs:attribute name="toType" type="xs:string"/>
</xs:complexType>
@@ -16227,11 +16246,21 @@ Sets the component name that this definition will apply to.
</xs:extension>
</xs:complexContent>
</xs:complexType>
+ <xs:complexType name="loadTransformer">
+ <xs:complexContent>
+ <xs:extension base="tns:transformer">
+ <xs:sequence/>
+ <xs:attribute name="packageScan" type="xs:string"/>
+ <xs:attribute name="defaults" type="xs:string"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
<xs:complexType name="transformersDefinition">
<xs:sequence>
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element name="dataFormatTransformer" type="tns:dataFormatTransformer"/>
<xs:element name="endpointTransformer" type="tns:endpointTransformer"/>
+ <xs:element name="loadTransformer" type="tns:loadTransformer"/>
<xs:element name="customTransformer" type="tns:customTransformer"/>
</xs:choice>
</xs:sequence>
diff --git a/components/camel-aws/camel-aws2-s3/pom.xml b/components/camel-aws/camel-aws2-s3/pom.xml
index 91b47ced72e..3b79056ec21 100644
--- a/components/camel-aws/camel-aws2-s3/pom.xml
+++ b/components/camel-aws/camel-aws2-s3/pom.xml
@@ -55,6 +55,14 @@
<artifactId>camel-health</artifactId>
</dependency>
+ <!-- optional CloudEvent support -->
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-cloudevents</artifactId>
+ <scope>provided</scope>
+ <optional>true</optional>
+ </dependency>
+
<!-- for testing -->
<dependency>
<groupId>org.apache.camel</groupId>
diff --git a/components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/transform/AWS2S3CloudEventDataTypeTransformer.java b/components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/transform/AWS2S3CloudEventDataTypeTransformer.java
new file mode 100644
index 00000000000..6d718d506a1
--- /dev/null
+++ b/components/camel-aws/camel-aws2-s3/src/main/java/org/apache/camel/component/aws2/s3/transform/AWS2S3CloudEventDataTypeTransformer.java
@@ -0,0 +1,54 @@
+/*
+ * 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.aws2.s3.transform;
+
+import java.util.Map;
+
+import org.apache.camel.Message;
+import org.apache.camel.component.aws2.s3.AWS2S3Constants;
+import org.apache.camel.component.cloudevents.CloudEvent;
+import org.apache.camel.component.cloudevents.CloudEvents;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
+
+/**
+ * Data type transformer converts AWS S3 get object response to CloudEvent v1_0 data format. The data type sets Camel
+ * specific CloudEvent headers with values extracted from AWS S3 get object response.
+ */
+@DataTypeTransformer(name = "aws2-s3:application-cloudevents")
+public class AWS2S3CloudEventDataTypeTransformer extends Transformer {
+
+ @Override
+ public void transform(Message message, DataType fromType, DataType toType) {
+ final Map<String, Object> headers = message.getHeaders();
+
+ CloudEvent cloudEvent = CloudEvents.v1_0;
+ headers.putIfAbsent(CloudEvent.CAMEL_CLOUD_EVENT_ID, message.getExchange().getExchangeId());
+ headers.putIfAbsent(CloudEvent.CAMEL_CLOUD_EVENT_VERSION, cloudEvent.version());
+ headers.put(CloudEvent.CAMEL_CLOUD_EVENT_TYPE, "org.apache.camel.event.aws.s3.getObject");
+
+ if (message.getHeaders().containsKey(AWS2S3Constants.BUCKET_NAME)) {
+ headers.put(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE,
+ "aws.s3.bucket." + message.getHeader(AWS2S3Constants.BUCKET_NAME, String.class));
+ }
+
+ headers.put(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT, message.getHeader(AWS2S3Constants.KEY, String.class));
+ headers.put(CloudEvent.CAMEL_CLOUD_EVENT_TIME, cloudEvent.getEventTime(message.getExchange()));
+ }
+}
diff --git a/components/camel-aws/camel-aws2-s3/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/aws2-s3-application-cloudevents b/components/camel-aws/camel-aws2-s3/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/aws2-s3-application-cloudevents
new file mode 100644
index 00000000000..ec5793a97f6
--- /dev/null
+++ b/components/camel-aws/camel-aws2-s3/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/aws2-s3-application-cloudevents
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.component.aws2.s3.transform.AWS2S3CloudEventDataTypeTransformer
diff --git a/components/camel-aws/camel-aws2-s3/src/test/java/org/apache/camel/component/aws2/s3/transform/AWS2S3CloudEventDataTypeTransformerTest.java b/components/camel-aws/camel-aws2-s3/src/test/java/org/apache/camel/component/aws2/s3/transform/AWS2S3CloudEventDataTypeTransformerTest.java
new file mode 100644
index 00000000000..89011c482ab
--- /dev/null
+++ b/components/camel-aws/camel-aws2-s3/src/test/java/org/apache/camel/component/aws2/s3/transform/AWS2S3CloudEventDataTypeTransformerTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.aws2.s3.transform;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.aws2.s3.AWS2S3Constants;
+import org.apache.camel.component.cloudevents.CloudEvent;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.engine.TransformerKey;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class AWS2S3CloudEventDataTypeTransformerTest {
+
+ private final DefaultCamelContext camelContext = new DefaultCamelContext();
+
+ private final AWS2S3CloudEventDataTypeTransformer transformer = new AWS2S3CloudEventDataTypeTransformer();
+
+ @Test
+ void shouldMapToCloudEvent() throws Exception {
+ Exchange exchange = new DefaultExchange(camelContext);
+
+ exchange.getMessage().setHeader(AWS2S3Constants.KEY, "test1.txt");
+ exchange.getMessage().setHeader(AWS2S3Constants.BUCKET_NAME, "myBucket");
+ exchange.getMessage().setHeader(AWS2S3Constants.CONTENT_TYPE, "text/plain");
+ exchange.getMessage().setHeader(AWS2S3Constants.CONTENT_ENCODING, StandardCharsets.UTF_8.toString());
+ exchange.getMessage().setBody(new ByteArrayInputStream("Test1".getBytes(StandardCharsets.UTF_8)));
+ transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+ Assertions.assertTrue(exchange.getMessage().hasHeaders());
+ Assertions.assertTrue(exchange.getMessage().getHeaders().containsKey(AWS2S3Constants.KEY));
+ assertEquals("org.apache.camel.event.aws.s3.getObject",
+ exchange.getMessage().getHeader(CloudEvent.CAMEL_CLOUD_EVENT_TYPE));
+ assertEquals("test1.txt", exchange.getMessage().getHeader(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT));
+ assertEquals("aws.s3.bucket.myBucket", exchange.getMessage().getHeader(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE));
+ }
+
+ @Test
+ public void shouldLookupDataTypeTransformer() throws Exception {
+ Transformer transformer = camelContext.getTransformerRegistry()
+ .resolveTransformer(new TransformerKey("aws2-s3:application-cloudevents"));
+ Assertions.assertNotNull(transformer);
+ Assertions.assertEquals(AWS2S3CloudEventDataTypeTransformer.class, transformer.getClass());
+
+ }
+}
diff --git a/components/camel-aws/camel-aws2-s3/src/test/java/org/apache/camel/component/aws2/s3/transform/AWS2S3TransformCloudEventsTest.java b/components/camel-aws/camel-aws2-s3/src/test/java/org/apache/camel/component/aws2/s3/transform/AWS2S3TransformCloudEventsTest.java
new file mode 100644
index 00000000000..4069f885e4a
--- /dev/null
+++ b/components/camel-aws/camel-aws2-s3/src/test/java/org/apache/camel/component/aws2/s3/transform/AWS2S3TransformCloudEventsTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.aws2.s3.transform;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.aws2.s3.AWS2S3Constants;
+import org.apache.camel.component.aws2.s3.AWS2S3Operations;
+import org.apache.camel.component.cloudevents.CloudEvent;
+import org.apache.camel.component.cloudevents.CloudEvents;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class AWS2S3TransformCloudEventsTest extends CamelTestSupport {
+ protected MockEndpoint resultEndpoint;
+
+ @Test
+ public void testCloudEventDataTypeTransformation() throws Exception {
+ resultEndpoint.expectedBodiesReceived("Hello World!");
+
+ Exchange exchange = template.request("direct:start", new Processor() {
+ @Override
+ public void process(Exchange exchange) {
+ exchange.getMessage().setHeader(AWS2S3Constants.BUCKET_NAME, "mycamel");
+ exchange.getMessage().setHeader(AWS2S3Constants.KEY, "camel.txt");
+ exchange.getMessage().setHeader(AWS2S3Constants.S3_OPERATION, AWS2S3Operations.getObject);
+ exchange.getMessage().setBody("Hello");
+ }
+ });
+
+ resultEndpoint.assertIsSatisfied();
+ CloudEvent cloudEvent = CloudEvents.v1_0;
+ Message received = exchange.getMessage();
+ Assertions.assertEquals("org.apache.camel.event.aws.s3.getObject",
+ received.getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TYPE).http()));
+ Assertions.assertEquals("aws.s3.bucket.mycamel",
+ received.getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE).http()));
+ Assertions.assertEquals(cloudEvent.version(),
+ received.getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_VERSION).http()));
+ Assertions.assertEquals("Hello World!", received.getBody());
+ }
+
+ @Override
+ @BeforeEach
+ public void setUp() throws Exception {
+ super.setUp();
+
+ resultEndpoint = getMockEndpoint("mock:result");
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ public void configure() {
+ from("direct:start")
+ .inputType("aws2-s3:application-cloudevents")
+ .setBody(body().append(" World!"))
+ .outputType("http:application-cloudevents")
+ .to("mock:result");
+ }
+ };
+ }
+}
diff --git a/components/camel-cloudevents/pom.xml b/components/camel-cloudevents/pom.xml
index f61eba3a973..b1900cc229e 100644
--- a/components/camel-cloudevents/pom.xml
+++ b/components/camel-cloudevents/pom.xml
@@ -44,6 +44,13 @@
<artifactId>camel-support</artifactId>
</dependency>
+ <!-- testing -->
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-test-junit5</artifactId>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
</project>
diff --git a/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/CloudEvent.java b/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/CloudEvent.java
index 0193549d8f1..ba3fc3d430a 100644
--- a/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/CloudEvent.java
+++ b/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/CloudEvent.java
@@ -16,6 +16,10 @@
*/
package org.apache.camel.component.cloudevents;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.Objects;
import java.util.Optional;
@@ -36,6 +40,9 @@ public interface CloudEvent {
String CAMEL_CLOUD_EVENT_EXTENSIONS = "CamelCloudEventExtensions";
String CAMEL_CLOUD_EVENT_CONTENT_TYPE = Exchange.CONTENT_TYPE;
+ String DEFAULT_CAMEL_CLOUD_EVENT_TYPE = "org.apache.camel.event";
+ String DEFAULT_CAMEL_CLOUD_EVENT_SOURCE = "org.apache.camel";
+
/**
* The CloudEvent spec version.
*/
@@ -65,6 +72,15 @@ public interface CloudEvent {
.orElseThrow(() -> new IllegalArgumentException("Unable to find attribute with id: " + id));
}
+ /**
+ * Construct event time from given Camel exchange.
+ */
+ default String getEventTime(Exchange exchange) {
+ final ZonedDateTime created
+ = ZonedDateTime.ofInstant(Instant.ofEpochMilli(exchange.getCreated()), ZoneId.systemDefault());
+ return DateTimeFormatter.ISO_INSTANT.format(created);
+ }
+
/**
* Mandatory find http attribute by id.
*/
diff --git a/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/transformer/CloudEventHttpDataTypeTransformer.java b/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/transformer/CloudEventHttpDataTypeTransformer.java
new file mode 100644
index 00000000000..c52c9af460e
--- /dev/null
+++ b/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/transformer/CloudEventHttpDataTypeTransformer.java
@@ -0,0 +1,69 @@
+/*
+ * 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.cloudevents.transformer;
+
+import java.util.Map;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.component.cloudevents.CloudEvent;
+import org.apache.camel.component.cloudevents.CloudEvents;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
+
+/**
+ * Data type represents a default Camel CloudEvent V1 Http binding. The data type reads Camel specific CloudEvent
+ * headers and transforms these to Http headers according to the CloudEvents Http binding specification. Sets default
+ * values for CloudEvent attributes such as the Http content type header, event source, event type.
+ */
+@DataTypeTransformer(name = "http:application-cloudevents")
+public class CloudEventHttpDataTypeTransformer extends Transformer {
+
+ @Override
+ public void transform(Message message, DataType fromType, DataType toType) {
+ final Map<String, Object> headers = message.getHeaders();
+
+ CloudEvent cloudEvent = CloudEvents.v1_0;
+ headers.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_ID).http(),
+ headers.getOrDefault(CloudEvent.CAMEL_CLOUD_EVENT_ID, message.getExchange().getExchangeId()));
+ headers.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_VERSION).http(),
+ headers.getOrDefault(CloudEvent.CAMEL_CLOUD_EVENT_VERSION, cloudEvent.version()));
+ headers.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TYPE).http(),
+ headers.getOrDefault(CloudEvent.CAMEL_CLOUD_EVENT_TYPE, CloudEvent.DEFAULT_CAMEL_CLOUD_EVENT_TYPE));
+ headers.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE).http(),
+ headers.getOrDefault(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE, CloudEvent.DEFAULT_CAMEL_CLOUD_EVENT_SOURCE));
+
+ if (headers.containsKey(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT)) {
+ headers.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT).http(),
+ headers.get(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT));
+ }
+
+ if (headers.containsKey(CloudEvent.CAMEL_CLOUD_EVENT_DATA_CONTENT_TYPE)) {
+ headers.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_DATA_CONTENT_TYPE).http(),
+ headers.get(CloudEvent.CAMEL_CLOUD_EVENT_DATA_CONTENT_TYPE));
+ }
+
+ headers.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TIME).http(),
+ headers.getOrDefault(CloudEvent.CAMEL_CLOUD_EVENT_TIME, cloudEvent.getEventTime(message.getExchange())));
+ headers.putIfAbsent(Exchange.CONTENT_TYPE,
+ headers.getOrDefault(CloudEvent.CAMEL_CLOUD_EVENT_CONTENT_TYPE, "application/json"));
+
+ cloudEvent.attributes().stream().map(CloudEvent.Attribute::id).forEach(headers::remove);
+ }
+}
diff --git a/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/transformer/CloudEventJsonDataTypeTransformer.java b/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/transformer/CloudEventJsonDataTypeTransformer.java
new file mode 100644
index 00000000000..1eef7d27fab
--- /dev/null
+++ b/components/camel-cloudevents/src/main/java/org/apache/camel/component/cloudevents/transformer/CloudEventJsonDataTypeTransformer.java
@@ -0,0 +1,88 @@
+/*
+ * 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.cloudevents.transformer;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.component.cloudevents.CloudEvent;
+import org.apache.camel.component.cloudevents.CloudEvents;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
+
+/**
+ * Data type represents a default Camel CloudEvent V1 Json format binding. The data type reads Camel specific CloudEvent
+ * headers and transforms these to a Json object representing the CloudEvents Json format specification. Sets default
+ * values for CloudEvent attributes such as the Http content type header, event source, event type.
+ */
+@DataTypeTransformer(name = "application-cloudevents+json")
+public class CloudEventJsonDataTypeTransformer extends Transformer {
+
+ @Override
+ public void transform(Message message, DataType fromType, DataType toType) {
+ final Map<String, Object> headers = message.getHeaders();
+
+ Map<String, Object> cloudEventAttributes = new HashMap<>();
+ CloudEvent cloudEvent = CloudEvents.v1_0;
+ for (CloudEvent.Attribute attribute : cloudEvent.attributes()) {
+ if (headers.containsKey(attribute.id())) {
+ cloudEventAttributes.put(attribute.json(), headers.get(attribute.id()));
+ }
+ }
+
+ cloudEventAttributes.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_VERSION).json(),
+ cloudEvent.version());
+ cloudEventAttributes.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_ID).json(),
+ message.getExchange().getExchangeId());
+ cloudEventAttributes.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TYPE).json(),
+ CloudEvent.DEFAULT_CAMEL_CLOUD_EVENT_TYPE);
+ cloudEventAttributes.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE).json(),
+ CloudEvent.DEFAULT_CAMEL_CLOUD_EVENT_SOURCE);
+
+ cloudEventAttributes.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TIME).json(),
+ cloudEvent.getEventTime(message.getExchange()));
+
+ cloudEventAttributes.putIfAbsent("data", message.getBody(String.class));
+ cloudEventAttributes.putIfAbsent(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_DATA_CONTENT_TYPE).json(),
+ headers.getOrDefault(CloudEvent.CAMEL_CLOUD_EVENT_CONTENT_TYPE, "application/json"));
+
+ headers.put(Exchange.CONTENT_TYPE, "application/cloudevents+json");
+
+ message.setBody(createCouldEventJsonObject(cloudEventAttributes));
+
+ cloudEvent.attributes().stream().map(CloudEvent.Attribute::id).forEach(headers::remove);
+ }
+
+ private String createCouldEventJsonObject(Map<String, Object> cloudEventAttributes) {
+ StringBuilder builder = new StringBuilder("{");
+
+ cloudEventAttributes.forEach((key, value) -> {
+ builder.append(" ").append("\"").append(key).append("\"").append(":").append("\"").append(value).append("\"")
+ .append(",");
+ });
+
+ if (!cloudEventAttributes.isEmpty()) {
+ builder.deleteCharAt(builder.lastIndexOf(","));
+ }
+
+ return builder.append("}").toString();
+ }
+}
diff --git a/components/camel-cloudevents/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/application-cloudevents-json b/components/camel-cloudevents/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/application-cloudevents-json
new file mode 100644
index 00000000000..d380ef770b9
--- /dev/null
+++ b/components/camel-cloudevents/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/application-cloudevents-json
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.component.cloudevents.transformer.CloudEventJsonDataTypeTransformer
diff --git a/components/camel-cloudevents/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/http-application-cloudevents b/components/camel-cloudevents/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/http-application-cloudevents
new file mode 100644
index 00000000000..ca4580b0f73
--- /dev/null
+++ b/components/camel-cloudevents/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/http-application-cloudevents
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.component.cloudevents.transformer.CloudEventHttpDataTypeTransformer
diff --git a/components/camel-cloudevents/src/test/java/org/apache/camel/component/cloudevents/transformer/CloudEventHttpDataTypeTransformerTest.java b/components/camel-cloudevents/src/test/java/org/apache/camel/component/cloudevents/transformer/CloudEventHttpDataTypeTransformerTest.java
new file mode 100644
index 00000000000..d4a864a7f6a
--- /dev/null
+++ b/components/camel-cloudevents/src/test/java/org/apache/camel/component/cloudevents/transformer/CloudEventHttpDataTypeTransformerTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.cloudevents.transformer;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.cloudevents.CloudEvent;
+import org.apache.camel.component.cloudevents.CloudEvents;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.engine.TransformerKey;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class CloudEventHttpDataTypeTransformerTest {
+
+ private final DefaultCamelContext camelContext = new DefaultCamelContext();
+
+ private final CloudEventHttpDataTypeTransformer transformer = new CloudEventHttpDataTypeTransformer();
+
+ @Test
+ void shouldMapToHttpCloudEvent() throws Exception {
+ Exchange exchange = new DefaultExchange(camelContext);
+
+ exchange.getMessage().setHeader(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT, "test1.txt");
+ exchange.getMessage().setHeader(CloudEvent.CAMEL_CLOUD_EVENT_TYPE, "org.apache.camel.event.test");
+ exchange.getMessage().setHeader(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE, "org.apache.camel.test");
+ exchange.getMessage().setHeader(CloudEvent.CAMEL_CLOUD_EVENT_CONTENT_TYPE, "text/plain");
+ exchange.getMessage().setBody(new ByteArrayInputStream("Test1".getBytes(StandardCharsets.UTF_8)));
+
+ transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+ CloudEvent cloudEvent = CloudEvents.v1_0;
+ assertTrue(exchange.getMessage().hasHeaders());
+ assertEquals(exchange.getExchangeId(),
+ exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_ID).http()));
+ assertEquals(cloudEvent.version(),
+ exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_VERSION).http()));
+ assertEquals("org.apache.camel.event.test",
+ exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TYPE).http()));
+ assertEquals("test1.txt",
+ exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT).http()));
+ assertEquals("org.apache.camel.test",
+ exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE).http()));
+ assertTrue(exchange.getMessage().getHeaders()
+ .containsKey(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TIME).http()));
+ assertEquals("text/plain", exchange.getMessage().getHeader(Exchange.CONTENT_TYPE));
+ assertEquals("Test1", exchange.getMessage().getBody(String.class));
+
+ assertNull(exchange.getMessage().getHeader(CloudEvent.CAMEL_CLOUD_EVENT_TYPE));
+ assertNull(exchange.getMessage().getHeader(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE));
+ assertNull(exchange.getMessage().getHeader(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT));
+ }
+
+ @Test
+ void shouldSetDefaultCloudEventAttributes() throws Exception {
+ Exchange exchange = new DefaultExchange(camelContext);
+
+ exchange.getMessage().setBody(new ByteArrayInputStream("{}".getBytes(StandardCharsets.UTF_8)));
+
+ transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+ CloudEvent cloudEvent = CloudEvents.v1_0;
+ assertTrue(exchange.getMessage().hasHeaders());
+ assertEquals(exchange.getExchangeId(),
+ exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_ID).http()));
+ assertEquals(cloudEvent.version(),
+ exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_VERSION).http()));
+ assertEquals(CloudEvent.DEFAULT_CAMEL_CLOUD_EVENT_TYPE,
+ exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TYPE).http()));
+ assertNull(exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT).http()));
+ assertEquals(CloudEvent.DEFAULT_CAMEL_CLOUD_EVENT_SOURCE,
+ exchange.getMessage().getHeader(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE).http()));
+ assertTrue(exchange.getMessage().getHeaders()
+ .containsKey(cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TIME).http()));
+ assertEquals("application/json", exchange.getMessage().getHeader(Exchange.CONTENT_TYPE));
+ assertEquals("{}", exchange.getMessage().getBody(String.class));
+ }
+
+ @Test
+ public void shouldLookupTransformer() throws Exception {
+ Transformer transformer
+ = camelContext.getTransformerRegistry().resolveTransformer(new TransformerKey("http:application-cloudevents"));
+ Assertions.assertNotNull(transformer);
+ Assertions.assertEquals(CloudEventHttpDataTypeTransformer.class, transformer.getClass());
+ }
+}
diff --git a/components/camel-cloudevents/src/test/java/org/apache/camel/component/cloudevents/transformer/CloudEventJsonDataTypeTransformerTest.java b/components/camel-cloudevents/src/test/java/org/apache/camel/component/cloudevents/transformer/CloudEventJsonDataTypeTransformerTest.java
new file mode 100644
index 00000000000..02b223e10a1
--- /dev/null
+++ b/components/camel-cloudevents/src/test/java/org/apache/camel/component/cloudevents/transformer/CloudEventJsonDataTypeTransformerTest.java
@@ -0,0 +1,103 @@
+/*
+ * 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.cloudevents.transformer;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.cloudevents.CloudEvent;
+import org.apache.camel.component.cloudevents.CloudEvents;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.engine.TransformerKey;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class CloudEventJsonDataTypeTransformerTest {
+
+ private final DefaultCamelContext camelContext = new DefaultCamelContext();
+
+ private final CloudEventJsonDataTypeTransformer transformer = new CloudEventJsonDataTypeTransformer();
+
+ @Test
+ void shouldMapToJsonCloudEventFormat() throws Exception {
+ Exchange exchange = new DefaultExchange(camelContext);
+
+ exchange.getMessage().setHeader(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT, "test1.txt");
+ exchange.getMessage().setHeader(CloudEvent.CAMEL_CLOUD_EVENT_TYPE, "org.apache.camel.event.test");
+ exchange.getMessage().setHeader(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE, "org.apache.camel.test");
+ exchange.getMessage().setHeader(CloudEvent.CAMEL_CLOUD_EVENT_CONTENT_TYPE, "text/plain");
+ exchange.getMessage().setBody(new ByteArrayInputStream("Test1".getBytes(StandardCharsets.UTF_8)));
+
+ transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+ CloudEvent cloudEvent = CloudEvents.v1_0;
+ assertTrue(exchange.getMessage().hasHeaders());
+ assertEquals("application/cloudevents+json", exchange.getMessage().getHeader(Exchange.CONTENT_TYPE));
+ assertTrue(exchange.getMessage().getBody(String.class).contains(String.format("\"%s\":\"%s\"",
+ cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_ID).json(), exchange.getExchangeId())));
+ assertTrue(exchange.getMessage().getBody(String.class).contains(String.format("\"%s\":\"org.apache.camel.event.test\"",
+ cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TYPE).json())));
+ assertTrue(exchange.getMessage().getBody(String.class).contains(String.format("\"%s\":\"org.apache.camel.test\"",
+ cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE).json())));
+ assertTrue(exchange.getMessage().getBody(String.class).contains(String.format("\"%s\":\"text/plain\"",
+ cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_DATA_CONTENT_TYPE).json())));
+ assertTrue(exchange.getMessage().getBody(String.class).contains("\"data\":\"Test1\""));
+
+ assertNull(exchange.getMessage().getHeader(CloudEvent.CAMEL_CLOUD_EVENT_TYPE));
+ assertNull(exchange.getMessage().getHeader(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE));
+ assertNull(exchange.getMessage().getHeader(CloudEvent.CAMEL_CLOUD_EVENT_SUBJECT));
+ }
+
+ @Test
+ void shouldSetDefaultCloudEventAttributes() throws Exception {
+ Exchange exchange = new DefaultExchange(camelContext);
+
+ exchange.getMessage().setBody(new ByteArrayInputStream("Test".getBytes(StandardCharsets.UTF_8)));
+
+ transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+ CloudEvent cloudEvent = CloudEvents.v1_0;
+ assertTrue(exchange.getMessage().hasHeaders());
+ assertEquals("application/cloudevents+json", exchange.getMessage().getHeader(Exchange.CONTENT_TYPE));
+ assertTrue(exchange.getMessage().getBody(String.class).contains(String.format("\"%s\":\"%s\"",
+ cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_ID).json(), exchange.getExchangeId())));
+ assertTrue(exchange.getMessage().getBody(String.class).contains(String.format("\"%s\":\"org.apache.camel.event\"",
+ cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_TYPE).json())));
+ assertTrue(exchange.getMessage().getBody(String.class).contains(String.format("\"%s\":\"org.apache.camel\"",
+ cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_SOURCE).json())));
+ assertTrue(exchange.getMessage().getBody(String.class).contains(String.format("\"%s\":\"application/json\"",
+ cloudEvent.mandatoryAttribute(CloudEvent.CAMEL_CLOUD_EVENT_DATA_CONTENT_TYPE).json())));
+ assertTrue(exchange.getMessage().getBody(String.class).contains("\"data\":\"Test\""));
+ }
+
+ @Test
+ public void shouldLookupTransformer() throws Exception {
+ Transformer transformer
+ = camelContext.getTransformerRegistry().resolveTransformer(new TransformerKey("application-cloudevents+json"));
+ Assertions.assertNotNull(transformer);
+ Assertions.assertEquals(CloudEventJsonDataTypeTransformer.class, transformer.getClass());
+ }
+}
diff --git a/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/impl/transformer/SpringTransformerRouteTest.xml b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/impl/transformer/SpringTransformerRouteTest.xml
index 47ce89a6189..319600d9bfe 100644
--- a/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/impl/transformer/SpringTransformerRouteTest.xml
+++ b/components/camel-spring-xml/src/test/resources/org/apache/camel/spring/impl/transformer/SpringTransformerRouteTest.xml
@@ -30,16 +30,18 @@
<bean id="otherToXOrder" class="org.apache.camel.processor.transformer.TransformerRouteTest$OtherToXOrderTransformer"/>
<bean id="xOrderResponseToOther" class="org.apache.camel.processor.transformer.TransformerRouteTest$XOrderResponseToOtherTransformer"/>
<bean id="myMyDataTypeFormatDef" class="org.apache.camel.processor.transformer.TransformerRouteTest$MyDataFormatDefinition"/>
-
+
<camelContext xmlns="http://camel.apache.org/schema/spring">
-
+
<endpoint id="myXmlEndpoint" uri="direct:endpointXmlTransformer"/>
<transformers>
+ <loadTransformer defaults="true"/>
+ <loadTransformer packageScan="org.apache.camel.processor.transformer.custom"/>
<dataFormatTransformer scheme="json">
<custom ref="myJsonDataFormatDef"/>
</dataFormatTransformer>
- <dataFormatTransformer scheme="myDataType">
+ <dataFormatTransformer name="myDataType">
<custom ref="myMyDataTypeFormatDef"/>
</dataFormatTransformer>
<endpointTransformer ref="myXmlEndpoint" fromType="xml:XmlXOrder" toType="java:org.apache.camel.processor.transformer.TransformerRouteTest$XOrder"/>
@@ -74,26 +76,26 @@
<setBody><constant>response</constant></setBody>
<to uri="mock:xyzresult"/>
</route>
-
+
<route>
<from uri="direct:dataFormat"/>
<inputType urn="json:JsonXOrder"/>
<outputType urn="json:JsonXOrderResponse"/>
<to uri="direct:xyz" pattern="InOut"/>
</route>
-
+
<route>
<from uri="direct:endpoint"/>
<inputType urn="xml:XmlXOrder"/>
<outputType urn="xml:XmlXOrderResponse"/>
<to uri="direct:xyz" pattern="InOut"/>
</route>
-
+
<route>
<from uri="direct:endpointXmlTransformer"/>
<process ref="myXmlProcessor"/>
</route>
-
+
<route>
<from uri="direct:custom"/>
<inputType urn="other:OtherXOrder"/>
@@ -114,5 +116,5 @@
</route>
</camelContext>
-
+
</beans>
diff --git a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
index 33cf3735b90..0a7464354ec 100644
--- a/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
+++ b/core/camel-api/src/main/java/org/apache/camel/CamelContext.java
@@ -948,10 +948,10 @@ public interface CamelContext extends CamelContextLifecycle, RuntimeConfiguratio
/**
* Resolve a transformer given a scheme
*
- * @param model data model name.
- * @return the resolved transformer, or <tt>null</tt> if not found
+ * @param name the transformer name, usually a combination of some scheme and name.
+ * @return the resolved transformer, or <tt>null</tt> if not found
*/
- Transformer resolveTransformer(String model);
+ Transformer resolveTransformer(String name);
/**
* Resolve a transformer given from/to data type.
@@ -1408,8 +1408,8 @@ public interface CamelContext extends CamelContextLifecycle, RuntimeConfiguratio
/**
* Whether to enable using data type on Camel messages.
* <p/>
- * Data type are automatic turned on if one ore more routes has been explicit configured with input and output
- * types. Otherwise data type is default off.
+ * Data type are automatic turned on if one or more routes has been explicit configured with input and output types.
+ * Otherwise, data type is default off.
*
* @return <tt>true</tt> if data type is enabled
*/
@@ -1418,8 +1418,8 @@ public interface CamelContext extends CamelContextLifecycle, RuntimeConfiguratio
/**
* Whether to enable using data type on Camel messages.
* <p/>
- * Data type are automatic turned on if one ore more routes has been explicit configured with input and output
- * types. Otherwise data type is default off.
+ * Data type are automatic turned on if one or more routes has been explicit configured with input and output types.
+ * Otherwise, data type is default off.
*
* @param useDataType <tt>true</tt> to enable data type on Camel messages.
*/
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/DataType.java b/core/camel-api/src/main/java/org/apache/camel/spi/DataType.java
index d741a81d956..333c262b47f 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/DataType.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/DataType.java
@@ -24,10 +24,16 @@ import org.apache.camel.util.StringHelper;
* Java class doesn't always explain the data type completely, for example XML and JSON data format is sometimes
* serialized as a {@code String}, {@code InputStream} or etc. The {@link DataTypeAware} message stores the DataType as
* a part of the message to carry those data type information even if it's marshaled, so that it could be leveraged to
- * detect required {@link Transformer} and {@link Validator}. DataType consists of two parts, 'model' and 'name'. Its
- * string representation is 'model:name' connected with colon. For example 'java:com.example.Order', 'xml:ABCOrder' or
- * 'json:XYZOrder'. These type name other than java class name allows the message to carry the name of the message data
- * structure even if it's marshaled.
+ * detect required {@link Transformer} and {@link Validator}. DataType URN consists of two parts, 'scheme' and 'name'.
+ *
+ * Its string representation is 'scheme:name' connected with colon. For example 'java:com.example.Order', 'xml:ABCOrder'
+ * or 'json:XYZOrder'. These type name other than java class name allows the message to carry the name of the message
+ * data structure even if it's marshaled.
+ * <p/>
+ * The scheme can also be used to associate the same DataType with different Camel components. For example
+ * `http:cloud-events` and `aws-s3:cloud-events` where the scheme relates to the respective component's scheme. This
+ * information could be leveraged to detect required {@link Transformer} and {@link Validator} implementations provided
+ * as part of these components.
*
* @see DataTypeAware
* @see Transformer
@@ -35,9 +41,13 @@ import org.apache.camel.util.StringHelper;
*/
public class DataType {
- public static final String JAVA_TYPE_PREFIX = "java";
+ public static final String DEFAULT_SCHEME = "camel";
+ public static final String JAVA_TYPE_SCHEME = "java";
+
+ public static final String ANY_TYPE_URN = DEFAULT_SCHEME + ":any";
+ public static final DataType ANY = new DataType(ANY_TYPE_URN);
- private String model;
+ private final String scheme;
private String name;
private boolean isJavaType;
private String typeString;
@@ -45,28 +55,35 @@ public class DataType {
public DataType(String urn) {
if (urn != null) {
String[] split = StringHelper.splitOnCharacter(urn, ":", 2);
- model = split[0];
- isJavaType = model.equals(JAVA_TYPE_PREFIX);
+ scheme = split[0];
+ isJavaType = scheme.equals(JAVA_TYPE_SCHEME);
if (split.length > 1) {
name = split[1];
}
+ } else {
+ scheme = DataType.ANY.scheme;
+ name = DataType.ANY.name;
}
}
public DataType(Class<?> clazz) {
- model = JAVA_TYPE_PREFIX;
+ scheme = JAVA_TYPE_SCHEME;
isJavaType = true;
name = clazz.getName();
}
- public String getModel() {
- return model;
+ public String getScheme() {
+ return scheme;
}
public String getName() {
return name;
}
+ public String getFullName() {
+ return name != null && !name.isEmpty() ? scheme + ":" + name : scheme;
+ }
+
public boolean isJavaType() {
return isJavaType;
}
@@ -74,23 +91,31 @@ public class DataType {
@Override
public String toString() {
if (this.typeString == null) {
- this.typeString = name != null && !name.isEmpty() ? model + ":" + name : model;
+ this.typeString = getFullName();
}
return this.typeString;
}
+ public static boolean isAnyType(DataType dataType) {
+ return dataType == null || DataType.ANY.equals(dataType);
+ }
+
+ public static boolean isJavaType(DataType dataType) {
+ return dataType != null && dataType.isJavaType();
+ }
+
@Override
public boolean equals(Object target) {
if (target instanceof DataType) {
DataType targetdt = (DataType) target;
- String targetModel = targetdt.getModel();
+ String targetScheme = targetdt.getScheme();
String targetName = targetdt.getName();
- if (targetModel == null) {
+ if (targetScheme == null) {
return false;
} else if (targetName == null) {
- return targetModel.equals(getModel()) && getName() == null;
+ return targetScheme.equals(getScheme()) && getName() == null;
} else {
- return targetModel.equals(getModel()) && targetName.equals(getName());
+ return targetScheme.equals(getScheme()) && targetName.equals(getName());
}
}
return false;
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/DataTypeTransformer.java b/core/camel-api/src/main/java/org/apache/camel/spi/DataTypeTransformer.java
new file mode 100644
index 00000000000..b047ed367bd
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/DataTypeTransformer.java
@@ -0,0 +1,60 @@
+/*
+ * 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.spi;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to configure a data type transformer with either specifying its name or from/to data types.
+ * <p/>
+ * The annotation is used by specific classpath scanning data type loaders to automatically add the data types to a
+ * registry.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Target({ ElementType.TYPE })
+public @interface DataTypeTransformer {
+
+ /**
+ * Data type transformer name. Identifies the data type transformer. Should be unique in the Camel context. Can be a
+ * combination of scheme and name. Is used to detect/reference the transformer when specifying input/output data
+ * types on routes.
+ *
+ * @return the data type transformer name.
+ */
+ String name() default "";
+
+ /**
+ * Data type representing the input of the transformation. Also used to detect the transformer.
+ *
+ * @return
+ */
+ String fromType() default "";
+
+ /**
+ * Data type representing the result of the transformation. Also used to detect the transformer.
+ *
+ * @return
+ */
+ String toType() default "";
+
+}
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/Transformer.java b/core/camel-api/src/main/java/org/apache/camel/spi/Transformer.java
index 814143a0869..b730fe5af12 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/Transformer.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/Transformer.java
@@ -20,6 +20,7 @@ import org.apache.camel.CamelContext;
import org.apache.camel.CamelContextAware;
import org.apache.camel.Message;
import org.apache.camel.support.service.ServiceSupport;
+import org.apache.camel.util.ObjectHelper;
/**
* <a href="http://camel.apache.org/transformer.html">Transformer</a> performs message transformation according to the
@@ -32,10 +33,31 @@ import org.apache.camel.support.service.ServiceSupport;
public abstract class Transformer extends ServiceSupport implements CamelContextAware {
private CamelContext camelContext;
- private String model;
+ private String name;
private DataType from;
private DataType to;
+ public Transformer() {
+ if (this.getClass().isAnnotationPresent(DataTypeTransformer.class)) {
+ DataTypeTransformer annotation = this.getClass().getAnnotation(DataTypeTransformer.class);
+ if (ObjectHelper.isNotEmpty(annotation.name())) {
+ this.name = annotation.name();
+ }
+
+ if (ObjectHelper.isNotEmpty(annotation.fromType())) {
+ this.from = new DataType(annotation.fromType());
+ }
+
+ if (ObjectHelper.isNotEmpty(annotation.toType())) {
+ this.to = new DataType(annotation.toType());
+ }
+ }
+ }
+
+ public Transformer(String name) {
+ this.name = name;
+ }
+
/**
* Perform data transformation with specified from/to type.
*
@@ -46,10 +68,12 @@ public abstract class Transformer extends ServiceSupport implements CamelContext
public abstract void transform(Message message, DataType from, DataType to) throws Exception;
/**
- * Get a data model which is supported by this transformer.
+ * Get the transformer name that represents the supported data type model.
+ *
+ * @return
*/
- public String getModel() {
- return model;
+ public String getName() {
+ return name;
}
/**
@@ -67,12 +91,32 @@ public abstract class Transformer extends ServiceSupport implements CamelContext
}
/**
- * Set data model.
+ * Set the name for this transformer. Usually a combination of scheme and name.
+ *
+ * @param name the transformer name
+ */
+ public Transformer setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * Set the scheme and/or name for this transformer. When using only a scheme the transformer applies to all
+ * transformations with that scheme.
*
- * @param model data model
+ * @param scheme supported data type scheme
+ * @param name transformer name
*/
- public Transformer setModel(String model) {
- this.model = model;
+ public Transformer setName(String scheme, String name) {
+ if (ObjectHelper.isNotEmpty(scheme)) {
+ if (ObjectHelper.isNotEmpty(name)) {
+ this.name = scheme + ":" + name;
+ } else {
+ this.name = scheme;
+ }
+ } else {
+ this.name = name;
+ }
return this;
}
@@ -108,7 +152,7 @@ public abstract class Transformer extends ServiceSupport implements CamelContext
@Override
public String toString() {
- return String.format("%s[scheme='%s', from='%s', to='%s']", this.getClass().getSimpleName(), model, from, to);
+ return String.format("%s[name='%s', from='%s', to='%s']", this.getClass().getSimpleName(), name, from, to);
}
@Override
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java b/core/camel-api/src/main/java/org/apache/camel/spi/TransformerLoader.java
similarity index 65%
copy from core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
copy to core/camel-api/src/main/java/org/apache/camel/spi/TransformerLoader.java
index 23827554acc..16f46d5754a 100644
--- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/TransformerLoader.java
@@ -14,16 +14,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.api.management.mbean;
-import org.apache.camel.api.management.ManagedAttribute;
+package org.apache.camel.spi;
-public interface ManagedTransformMBean extends ManagedProcessorMBean {
-
- @ManagedAttribute(description = "The language for the expression")
- String getExpressionLanguage();
+/**
+ * A pluggable strategy to load data types into a {@link TransformerRegistry}. Loads one to many data type transformers
+ * to the given registry.
+ */
+public interface TransformerLoader {
- @ManagedAttribute(description = "Expression to return the transformed message body (the new message body to use)")
- String getExpression();
+ /**
+ * A pluggable strategy to load transformers into a given registry.
+ *
+ * @param registry the registry the transformers get added to.
+ */
+ void load(TransformerRegistry registry);
}
diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/TransformerResolver.java b/core/camel-api/src/main/java/org/apache/camel/spi/TransformerResolver.java
new file mode 100644
index 00000000000..cf03dc13012
--- /dev/null
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/TransformerResolver.java
@@ -0,0 +1,54 @@
+/*
+ * 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.spi;
+
+import java.util.Locale;
+
+import org.apache.camel.CamelContext;
+
+/**
+ * Resolves data type transformers from given transformer key. This represents the opportunity to lazy load transformers
+ * via factory finder discovery mechanism.
+ */
+@FunctionalInterface
+public interface TransformerResolver<K> {
+
+ /**
+ * Attempts to resolve the transformer for the given key. Usually uses the factory finder URI to resolve the
+ * transformer by its name derived from the given key. Transformer names may use scheme and name as a combination in
+ * order to resolve component specific transformers. Usually implements a fallback resolving mechanism when no
+ * matching transformer is found (e.g. search for generic Camel transformers just using the name).
+ *
+ * @param key the transformer key.
+ * @param camelContext the current Camel context.
+ * @return data type transformer resolved via URI factory finder or null if not found.
+ */
+ Transformer resolve(K key, CamelContext camelContext);
+
+ /**
+ * Normalize transformer key to conform with factory finder resource path. Replaces all non supported characters
+ * such as slashes and colons to dashes.
+ *
+ * @param key the transformer key
+ * @return normalized String representation of the key
+ */
+ default String normalize(K key) {
+ return key.toString().replaceAll("[^A-Za-z0-9-]", "-").toLowerCase(Locale.US);
+ }
+
+}
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index e22568d641e..a282225893c 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -3867,8 +3867,8 @@ public abstract class AbstractCamelContext extends BaseService
}
@Override
- public Transformer resolveTransformer(String scheme) {
- return getTransformerRegistry().resolveTransformer(new TransformerKey(scheme));
+ public Transformer resolveTransformer(String name) {
+ return getTransformerRegistry().resolveTransformer(new TransformerKey(name));
}
@Override
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultTransformerRegistry.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultTransformerRegistry.java
index 23000c889df..cf3f8942e03 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultTransformerRegistry.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultTransformerRegistry.java
@@ -20,12 +20,17 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
import org.apache.camel.spi.DataType;
import org.apache.camel.spi.Transformer;
+import org.apache.camel.spi.TransformerLoader;
import org.apache.camel.spi.TransformerRegistry;
+import org.apache.camel.spi.TransformerResolver;
import org.apache.camel.support.CamelContextHelper;
import org.apache.camel.support.service.ServiceHelper;
import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Default implementation of {@link org.apache.camel.spi.TransformerRegistry}.
@@ -33,8 +38,12 @@ import org.apache.camel.util.ObjectHelper;
public class DefaultTransformerRegistry extends AbstractDynamicRegistry<TransformerKey, Transformer>
implements TransformerRegistry<TransformerKey> {
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultTransformerRegistry.class);
+
private final Map<TransformerKey, TransformerKey> aliasMap;
+ private TransformerResolver<TransformerKey> transformerResolver;
+
public DefaultTransformerRegistry(CamelContext context) {
super(context, CamelContextHelper.getMaximumTransformerCacheSize(context));
this.aliasMap = new ConcurrentHashMap<>();
@@ -42,41 +51,107 @@ public class DefaultTransformerRegistry extends AbstractDynamicRegistry<Transfor
@Override
public Transformer resolveTransformer(TransformerKey key) {
- if (ObjectHelper.isEmpty(key.getScheme()) && key.getTo() == null) {
+ if (DataType.isAnyType(key.getFrom()) && DataType.isAnyType(key.getTo())) {
return null;
}
// try exact match
Transformer answer = get(aliasMap.getOrDefault(key, key));
- if (answer != null || ObjectHelper.isNotEmpty(key.getScheme())) {
+ if (answer != null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Found transformer {} for key {}", ObjectHelper.name(answer.getClass()), key);
+ }
+
return answer;
}
- // try wildcard match for next - add an alias if matched
+ // try wildcard match for transformers with matching data type scheme - add an alias if matched
TransformerKey alias = null;
- if (key.getFrom() != null && ObjectHelper.isNotEmpty(key.getFrom().getName())) {
- alias = new TransformerKey(new DataType(key.getFrom().getModel()), key.getTo());
+ if (!DataType.isAnyType(key.getFrom()) && ObjectHelper.isNotEmpty(key.getFrom().getName())) {
+ alias = new TransformerKey(new DataType(key.getFrom().getScheme()), key.getTo());
answer = get(alias);
}
if (answer == null && ObjectHelper.isNotEmpty(key.getTo().getName())) {
- alias = new TransformerKey(key.getFrom(), new DataType(key.getTo().getModel()));
+ alias = new TransformerKey(key.getFrom(), new DataType(key.getTo().getScheme()));
answer = get(alias);
}
- if (answer == null && key.getFrom() != null && ObjectHelper.isNotEmpty(key.getFrom().getName())
+ if (answer == null && !DataType.isAnyType(key.getFrom()) && ObjectHelper.isNotEmpty(key.getFrom().getName())
&& ObjectHelper.isNotEmpty(key.getTo().getName())) {
- alias = new TransformerKey(new DataType(key.getFrom().getModel()), new DataType(key.getTo().getModel()));
+ alias = new TransformerKey(new DataType(key.getFrom().getScheme()), new DataType(key.getTo().getScheme()));
answer = get(alias);
}
- if (answer == null && key.getFrom() != null) {
- alias = new TransformerKey(key.getFrom().getModel());
+
+ if (answer == null && !DataType.isAnyType(key.getTo())) {
+ alias = new TransformerKey(key.getTo());
answer = get(alias);
+
+ if (answer == null) {
+ alias = new TransformerKey(key.getTo().getScheme());
+ answer = get(alias);
+ }
}
- if (answer == null) {
- alias = new TransformerKey(key.getTo().getModel());
+
+ if (answer == null && !DataType.isAnyType(key.getFrom())) {
+ alias = new TransformerKey(key.getFrom());
answer = get(alias);
+
+ if (answer == null) {
+ alias = new TransformerKey(key.getFrom().getScheme());
+ answer = get(alias);
+ }
}
+
if (answer != null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Found transformer {} for key {} using alias {}", ObjectHelper.name(answer.getClass()), key, alias);
+ }
+
aliasMap.put(key, alias);
+ return answer;
+ }
+
+ if (!DataType.isJavaType(key.getTo())) {
+ answer = lazyLoadTransformer(new TransformerKey(key.getTo()));
+
+ if (answer != null) {
+ // Add lazy loaded transformer and an alias
+ TransformerKey transformerKey = TransformerKey.createFrom(answer);
+ put(transformerKey, answer);
+ if (!key.equals(transformerKey)) {
+ aliasMap.put(key, transformerKey);
+ }
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Found transformer {} for key {}", ObjectHelper.name(answer.getClass()), key);
+ }
+ }
+ }
+
+ return answer;
+ }
+
+ /**
+ * Tra to lazy load transformer either from Camel context as bean reference or via transformer resolver mechanism,
+ * e.g. doing a resource path lookup.
+ *
+ * @param key the transformer key.
+ * @return lazy loaded transformer or null if not found.
+ */
+ private Transformer lazyLoadTransformer(TransformerKey key) {
+ // Looking for matching beans in Camel registry first
+ Transformer answer = CamelContextHelper.lookup(context, key.toString(), Transformer.class);
+
+ if (answer == null) {
+ if (transformerResolver == null) {
+ TransformerResolver<?> contextResolver = context.getRegistry().findSingleByType(TransformerResolver.class);
+ if (contextResolver != null) {
+ transformerResolver = (TransformerResolver<TransformerKey>) contextResolver;
+ } else {
+ transformerResolver = new DefaultTransformerResolver();
+ }
+ }
+
+ // Try to lazy load transformer via resolver, e.g. with resource path lookup
+ answer = transformerResolver.resolve(key, context);
}
return answer;
@@ -86,7 +161,27 @@ public class DefaultTransformerRegistry extends AbstractDynamicRegistry<Transfor
public Transformer put(TransformerKey key, Transformer obj) {
// ensure transformer is started before its being used
ServiceHelper.startService(obj);
- return super.put(key, obj);
+
+ if (obj instanceof TransformerLoader) {
+ ((TransformerLoader) obj).load(this);
+ return obj;
+ } else {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Adding transformer for key {}", key);
+ }
+
+ return super.put(key, obj);
+ }
+ }
+
+ @Override
+ public void init() {
+ // if applicable set Camel context on all transformers
+ values().forEach(t -> {
+ if (((CamelContextAware) t).getCamelContext() == null) {
+ CamelContextAware.trySetCamelContext(t, context);
+ }
+ });
}
@Override
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultTransformerResolver.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultTransformerResolver.java
new file mode 100644
index 00000000000..6099e79ca31
--- /dev/null
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultTransformerResolver.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.impl.engine;
+
+import java.util.Optional;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.spi.TransformerResolver;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The default implementation of {@link org.apache.camel.spi.TransformerResolver} which tries to find components by
+ * using the URI scheme prefix and searching for a file of the URI scheme name in the
+ * <b>META-INF/services/org/apache/camel/datatype/transformer/</b> directory on the classpath.
+ */
+public class DefaultTransformerResolver implements TransformerResolver<TransformerKey> {
+
+ public static final String DATA_TYPE_TRANSFORMER_RESOURCE_PATH = "META-INF/services/org/apache/camel/datatype/transformer/";
+
+ private static final Logger LOG = LoggerFactory.getLogger(DefaultTransformerResolver.class);
+
+ @Override
+ public Transformer resolve(TransformerKey key, CamelContext context) {
+ String normalizedKey = normalize(key);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Resolving data type transformer for key {} via: {}{}", key, DATA_TYPE_TRANSFORMER_RESOURCE_PATH,
+ normalizedKey);
+ }
+
+ Optional<Transformer> transformer = findTransformer(normalizedKey, context);
+ if (LOG.isDebugEnabled() && transformer.isPresent()) {
+ LOG.debug("Found data type transformer for key {} via type: {} via: {}{}", key,
+ ObjectHelper.name(transformer.getClass()), DATA_TYPE_TRANSFORMER_RESOURCE_PATH, normalizedKey);
+ }
+
+ transformer.ifPresent(t -> CamelContextAware.trySetCamelContext(t, context));
+
+ return transformer.orElse(null);
+ }
+
+ private Optional<Transformer> findTransformer(String key, CamelContext context) {
+ return context.getCamelContextExtension()
+ .getBootstrapFactoryFinder(DATA_TYPE_TRANSFORMER_RESOURCE_PATH)
+ .newInstance(key, Transformer.class);
+ }
+}
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultValidatorRegistry.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultValidatorRegistry.java
index 1314e058166..ef114820264 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultValidatorRegistry.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultValidatorRegistry.java
@@ -38,7 +38,7 @@ public class DefaultValidatorRegistry extends AbstractDynamicRegistry<ValidatorK
public Validator resolveValidator(ValidatorKey key) {
Validator answer = get(key);
if (answer == null && ObjectHelper.isNotEmpty(key.getType().getName())) {
- answer = get(new ValidatorKey(new DataType(key.getType().getModel())));
+ answer = get(new ValidatorKey(new DataType(key.getType().getScheme())));
}
return answer;
}
diff --git a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/TransformerKey.java b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/TransformerKey.java
index 8ce756b7d65..a74724467ef 100644
--- a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/TransformerKey.java
+++ b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/TransformerKey.java
@@ -18,6 +18,7 @@ package org.apache.camel.impl.engine;
import org.apache.camel.ValueHolder;
import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
import org.apache.camel.util.StringHelper;
/**
@@ -26,14 +27,16 @@ import org.apache.camel.util.StringHelper;
*/
public final class TransformerKey extends ValueHolder<String> {
- private String scheme;
- private DataType from;
- private DataType to;
+ private final DataType from;
+ private final DataType to;
- public TransformerKey(String scheme) {
- super(scheme);
- StringHelper.notEmpty(scheme, "scheme");
- this.scheme = scheme;
+ public TransformerKey(String toType) {
+ this(DataType.ANY, new DataType(toType));
+ StringHelper.notEmpty(toType, "toType");
+ }
+
+ public TransformerKey(DataType to) {
+ this(DataType.ANY, to);
}
public TransformerKey(DataType from, DataType to) {
@@ -42,12 +45,35 @@ public final class TransformerKey extends ValueHolder<String> {
this.to = to;
}
+ /**
+ * Create the string that represents this transformer key. Either uses both full names of from/to data types in
+ * combination or only uses the toType data type full name in case fromType is not specified.
+ *
+ * @param from
+ * @param to
+ * @return
+ */
private static String createKeyString(DataType from, DataType to) {
- return from + "/" + to;
+ if (DataType.isAnyType(from)) {
+ return to.getFullName();
+ }
+
+ return from.getFullName() + "/" + to.getFullName();
}
- public String getScheme() {
- return scheme;
+ /**
+ * Create the transformer key for the given transformer either using the transformer name or it's specified from/to
+ * data type name.
+ *
+ * @param answer
+ * @return
+ */
+ public static TransformerKey createFrom(Transformer answer) {
+ if (!DataType.isAnyType(answer.getFrom()) && !DataType.isAnyType(answer.getTo())) {
+ return new TransformerKey(answer.getFrom(), answer.getTo());
+ }
+
+ return new TransformerKey(answer.getName());
}
public DataType getFrom() {
diff --git a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
index 7a38fe8f0b4..15a4a6165bb 100644
--- a/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
+++ b/core/camel-core-engine/src/main/java/org/apache/camel/impl/DefaultCamelContext.java
@@ -922,9 +922,15 @@ public class DefaultCamelContext extends SimpleCamelContext implements ModelCame
}
private static ValueHolder<String> createTransformerKey(TransformerDefinition def) {
- return ObjectHelper.isNotEmpty(def.getScheme())
- ? new TransformerKey(def.getScheme())
- : new TransformerKey(new DataType(def.getFromType()), new DataType(def.getToType()));
+ if (ObjectHelper.isNotEmpty(def.getScheme())) {
+ return ObjectHelper.isNotEmpty(def.getName())
+ ? new TransformerKey(def.getScheme() + ":" + def.getName()) : new TransformerKey(def.getScheme());
+ }
+ if (ObjectHelper.isNotEmpty(def.getName())) {
+ return new TransformerKey(def.getName());
+ } else {
+ return new TransformerKey(new DataType(def.getFromType()), new DataType(def.getToType()));
+ }
}
}
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/transform.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/transform.json
index 5e37dc5dd65..85e827be37f 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/transform.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/transform.json
@@ -13,8 +13,10 @@
},
"properties": {
"expression": { "index": 0, "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jq", "js", "jsonpath", "language", "method", "mvel", "ognl", "python", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": fa [...]
- "disabled": { "index": 1, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
- "id": { "index": 2, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
- "description": { "index": 3, "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" }
+ "fromType": { "index": 1, "kind": "attribute", "displayName": "From Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "From type used in data type transformation." },
+ "toType": { "index": 2, "kind": "attribute", "displayName": "To Type", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "To type used as a target data type in the transformation." },
+ "disabled": { "index": 3, "kind": "attribute", "displayName": "Disabled", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether to disable this EIP from the route during build time. Once an EIP has been disabled then it cannot be enabled later at runtime." },
+ "id": { "index": 4, "kind": "attribute", "displayName": "Id", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the id of this node" },
+ "description": { "index": 5, "kind": "element", "displayName": "Description", "required": false, "type": "object", "javaType": "org.apache.camel.model.DescriptionDefinition", "deprecated": false, "autowired": false, "secret": false, "description": "Sets the description of this node" }
}
}
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/transformer/jaxb.index b/core/camel-core-model/src/generated/resources/org/apache/camel/model/transformer/jaxb.index
index af780ec37f0..73ef81d1fb4 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/transformer/jaxb.index
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/transformer/jaxb.index
@@ -2,5 +2,6 @@
CustomTransformerDefinition
DataFormatTransformerDefinition
EndpointTransformerDefinition
+LoadTransformerDefinition
TransformerDefinition
TransformersDefinition
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/transformer/transformers.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/transformer/transformers.json
index af5d7902054..1f2ae2ab00a 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/transformer/transformers.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/transformer/transformers.json
@@ -12,6 +12,6 @@
"output": false
},
"properties": {
- "transformers": { "index": 0, "kind": "element", "displayName": "Transformers", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.transformer.TransformerDefinition>", "oneOf": [ "customTransformer", "dataFormatTransformer", "endpointTransformer" ], "deprecated": false, "autowired": false, "secret": false, "description": "The configured transformers" }
+ "transformers": { "index": 0, "kind": "element", "displayName": "Transformers", "required": true, "type": "array", "javaType": "java.util.List<org.apache.camel.model.transformer.TransformerDefinition>", "oneOf": [ "customTransformer", "dataFormatTransformer", "endpointTransformer", "loadTransformer" ], "deprecated": false, "autowired": false, "secret": false, "description": "The configured transformers" }
}
}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/builder/TransformerBuilder.java b/core/camel-core-model/src/main/java/org/apache/camel/builder/TransformerBuilder.java
index a1a9ec74b7d..026939d1af3 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/builder/TransformerBuilder.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/builder/TransformerBuilder.java
@@ -22,9 +22,11 @@ import org.apache.camel.model.ModelCamelContext;
import org.apache.camel.model.transformer.CustomTransformerDefinition;
import org.apache.camel.model.transformer.DataFormatTransformerDefinition;
import org.apache.camel.model.transformer.EndpointTransformerDefinition;
+import org.apache.camel.model.transformer.LoadTransformerDefinition;
import org.apache.camel.model.transformer.TransformerDefinition;
import org.apache.camel.spi.DataType;
import org.apache.camel.spi.Transformer;
+import org.apache.camel.util.ObjectHelper;
/**
* A <a href="http://camel.apache.org/dsl.html">Java DSL</a> which is used to build a
@@ -35,16 +37,32 @@ import org.apache.camel.spi.Transformer;
public class TransformerBuilder {
private String scheme;
+ private String name;
private String from;
private String to;
private String uri;
private DataFormatDefinition dataFormat;
private Class<? extends Transformer> clazz;
private String beanRef;
+ private boolean defaults;
+ private String packageScan;
+
+ /**
+ * Set the transformer name under which the transformer gets referenced when specifying the input/output data type
+ * on routes. If you specify a transformer name that matches a data type scheme like 'csv' the transformer will be
+ * picked up for all of 'csv:*' from/to Java transformation. Note that the scheme matching is performed only when no
+ * exactly matched transformer exists.
+ *
+ * @param name transformer name
+ */
+ public TransformerBuilder name(String name) {
+ this.name = name;
+ return this;
+ }
/**
* Set the scheme name supported by the transformer. If you specify 'csv', the transformer will be picked up for all
- * of 'csv' from/to Java transformation. Note that the scheme matching is performed only when no exactly matched
+ * of 'csv:*' from/to Java transformation. Note that the scheme matching is performed only when no exactly matched
* transformer exists.
*
* @param scheme scheme name
@@ -136,11 +154,33 @@ public class TransformerBuilder {
return this;
}
+ /**
+ * Enables default transformers on the registry.
+ */
+ public TransformerBuilder withDefaults() {
+ resetType();
+ this.defaults = true;
+ return this;
+ }
+
+ /**
+ * Set the classpath location to scan for {@code Transformer} implementations. Usually these transformer
+ * implementations use {@code DataTypeTransformer} annotations to expose a transformer name and supported from/to
+ * data types.
+ */
+ public TransformerBuilder scan(String location) {
+ resetType();
+ this.packageScan = location;
+ return this;
+ }
+
private void resetType() {
this.uri = null;
this.dataFormat = null;
this.clazz = null;
this.beanRef = null;
+ this.defaults = false;
+ this.packageScan = null;
}
/**
@@ -167,12 +207,23 @@ public class TransformerBuilder {
CustomTransformerDefinition ctd = new CustomTransformerDefinition();
ctd.setRef(beanRef);
transformer = ctd;
+ } else if (defaults) {
+ LoadTransformerDefinition ltd = new LoadTransformerDefinition();
+ ltd.setDefaults("true");
+ transformer = ltd;
+ } else if (packageScan != null) {
+ LoadTransformerDefinition ltd = new LoadTransformerDefinition();
+ ltd.setPackageScan(packageScan);
+ transformer = ltd;
} else {
throw new IllegalArgumentException("No Transformer type was specified");
}
- if (scheme != null) {
+ if (ObjectHelper.isNotEmpty(scheme)) {
transformer.setScheme(scheme);
+ transformer.setName(name);
+ } else if (ObjectHelper.isNotEmpty(name)) {
+ transformer.setName(name);
} else {
transformer.setFromType(from);
transformer.setToType(to);
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
index e766c76f42b..11ff1d8dced 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/ProcessorDefinition.java
@@ -62,6 +62,7 @@ import org.apache.camel.resume.ResumeStrategy;
import org.apache.camel.spi.AsEndpointUri;
import org.apache.camel.spi.AsPredicate;
import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.DataType;
import org.apache.camel.spi.IdempotentRepository;
import org.apache.camel.spi.InterceptStrategy;
import org.apache.camel.spi.Metadata;
@@ -2453,6 +2454,33 @@ public abstract class ProcessorDefinition<Type extends ProcessorDefinition<Type>
return asType();
}
+ /**
+ * <a href="http://camel.apache.org/message-translator.html">Message Translator EIP:</a> Adds a processor which sets
+ * the body on the OUT message according to a data type transformation.
+ *
+ * @param fromType the data type representing the input of the transformation
+ * @param toType the data type representing the output of the transformation.
+ * @return the builder
+ */
+ public Type transform(DataType fromType, DataType toType) {
+ TransformDefinition answer = new TransformDefinition(fromType, toType);
+ addOutput(answer);
+ return asType();
+ }
+
+ /**
+ * <a href="http://camel.apache.org/message-translator.html">Message Translator EIP:</a> Adds a processor which sets
+ * the body on the OUT message according to a data type transformation.
+ *
+ * @param toType the data type representing the output of the transformation.
+ * @return the builder
+ */
+ public Type transform(DataType toType) {
+ TransformDefinition answer = new TransformDefinition(DataType.ANY, toType);
+ addOutput(answer);
+ return asType();
+ }
+
/**
* <a href="http://camel.apache.org/message-translator.html">Message Translator EIP:</a> Adds a processor which sets
* the body on the OUT message
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/TransformDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/TransformDefinition.java
index e53dea89b88..a6519b5de3c 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/TransformDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/TransformDefinition.java
@@ -18,10 +18,12 @@ package org.apache.camel.model;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlAttribute;
import jakarta.xml.bind.annotation.XmlRootElement;
import org.apache.camel.Expression;
import org.apache.camel.model.language.ExpressionDefinition;
+import org.apache.camel.spi.DataType;
import org.apache.camel.spi.Metadata;
/**
@@ -32,6 +34,12 @@ import org.apache.camel.spi.Metadata;
@XmlAccessorType(XmlAccessType.FIELD)
public class TransformDefinition extends ExpressionNode {
+ @XmlAttribute
+ private String fromType;
+
+ @XmlAttribute
+ private String toType;
+
public TransformDefinition() {
}
@@ -39,8 +47,21 @@ public class TransformDefinition extends ExpressionNode {
super(expression);
}
+ public TransformDefinition(DataType fromType, DataType toType) {
+ this.fromType = fromType.getFullName();
+ this.toType = toType.getFullName();
+ }
+
@Override
public String toString() {
+ if (toType != null) {
+ if (fromType != null) {
+ return "Transform[" + fromType + ", " + toType + "]";
+ } else {
+ return "Transform[" + toType + "]";
+ }
+ }
+
return "Transform[" + getExpression() + "]";
}
@@ -51,6 +72,14 @@ public class TransformDefinition extends ExpressionNode {
@Override
public String getLabel() {
+ if (toType != null) {
+ if (fromType != null) {
+ return "transform[" + fromType + ", " + toType + "]";
+ } else {
+ return "transform[" + toType + "]";
+ }
+ }
+
return "transform[" + getExpression() + "]";
}
@@ -63,4 +92,25 @@ public class TransformDefinition extends ExpressionNode {
super.setExpression(expression);
}
+ /**
+ * From type used in data type transformation.
+ */
+ public void setFromType(String fromType) {
+ this.fromType = fromType;
+ }
+
+ public String getFromType() {
+ return fromType;
+ }
+
+ /**
+ * To type used as a target data type in the transformation.
+ */
+ public void setToType(String toType) {
+ this.toType = toType;
+ }
+
+ public String getToType() {
+ return toType;
+ }
}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/LoadTransformerDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/LoadTransformerDefinition.java
new file mode 100644
index 00000000000..68a2630d392
--- /dev/null
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/LoadTransformerDefinition.java
@@ -0,0 +1,64 @@
+/*
+ * 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.model.transformer;
+
+import jakarta.xml.bind.annotation.XmlAccessType;
+import jakarta.xml.bind.annotation.XmlAccessorType;
+import jakarta.xml.bind.annotation.XmlAttribute;
+import jakarta.xml.bind.annotation.XmlType;
+
+import org.apache.camel.spi.Metadata;
+
+/**
+ * Loads one to many {@link org.apache.camel.spi.Transformer} via {@link org.apache.camel.spi.TransformerLoader}.
+ * Supports classpath scan to load transformer implementations configured for instance via annotation configuration.
+ */
+@Metadata(label = "transformation")
+@XmlType(name = "loadTransformer")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class LoadTransformerDefinition extends TransformerDefinition {
+
+ @XmlAttribute
+ private String packageScan;
+
+ @XmlAttribute
+ @Metadata(javaType = "java.lang.Boolean", defaultValue = "false")
+ private String defaults;
+
+ public String getDefaults() {
+ return defaults;
+ }
+
+ /**
+ * Enable loading of default transformers.
+ */
+ public void setDefaults(String defaults) {
+ this.defaults = defaults;
+ }
+
+ public String getPackageScan() {
+ return packageScan;
+ }
+
+ /**
+ * Set the classpath location to scan for annotated transformers.
+ */
+ public void setPackageScan(String packageScan) {
+ this.packageScan = packageScan;
+ }
+
+}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/TransformerDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/TransformerDefinition.java
index ef186710526..8006181630a 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/TransformerDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/TransformerDefinition.java
@@ -32,8 +32,15 @@ import org.apache.camel.spi.Metadata;
*
* If you specify from='java:com.example.ABC' and to='xml:XYZ', the transformer will be picked up when current message
* type is 'java:com.example.ABC' and expected message type is 'xml:XYZ'. If you specify from='java' to='xml', then it
- * will be picked up for all of Java to xml transformation. Also it's possible to specify scheme='xml' so that the
- * transformer will be picked up for all of Java to xml and xml to java transformation.
+ * will be picked up for all of Java to xml transformation.
+ *
+ * Also, it's possible to specify a transformer name that identifies the transformer. Usually the name is a combination
+ * of a scheme and a name that represents the supported data type name. The declared {@link InputTypeDefinition} and/or
+ * {@link OutputTypeDefinition} can then reference the transformer by its name.
+ *
+ * In case the transformer name should represent a data type scheme such as name='xml' that specific transformer will
+ * also be picked up for all of Java to xml and xml to Java transformation as a fallback when no matching transformer is
+ * found.
*/
@Metadata(label = "transformation")
@XmlType(name = "transformer")
@@ -43,6 +50,8 @@ public abstract class TransformerDefinition {
@XmlAttribute
private String scheme;
@XmlAttribute
+ private String name;
+ @XmlAttribute
private String fromType;
@XmlAttribute
private String toType;
@@ -56,12 +65,28 @@ public abstract class TransformerDefinition {
* of 'csv' from/to Java transformation. Note that the scheme matching is performed only when no exactly matched
* transformer exists.
*
- * @param scheme scheme name
+ * @param scheme the supported data type scheme
*/
public void setScheme(String scheme) {
this.scheme = scheme;
}
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Set the transformer name under which the transformer gets referenced when specifying the input/output data type
+ * on routes. If you specify a transformer name that matches a data type scheme like 'csv' the transformer will be
+ * picked up for all of 'csv:*' from/to Java transformation. Note that the scheme matching is performed only when no
+ * exactly matched transformer exists.
+ *
+ * @param name transformer name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
public String getFromType() {
return fromType;
}
diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/TransformersDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/TransformersDefinition.java
index fea9b233691..907fc405db5 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/TransformersDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/transformer/TransformersDefinition.java
@@ -37,6 +37,7 @@ public class TransformersDefinition {
@XmlElements({
@XmlElement(name = "dataFormatTransformer", type = DataFormatTransformerDefinition.class),
@XmlElement(name = "endpointTransformer", type = EndpointTransformerDefinition.class),
+ @XmlElement(name = "loadTransformer", type = LoadTransformerDefinition.class),
@XmlElement(name = "customTransformer", type = CustomTransformerDefinition.class) })
private List<TransformerDefinition> transformers;
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/ContractAdvice.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/ContractAdvice.java
index 7c5954fa24c..22cdc199be5 100644
--- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/ContractAdvice.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/ContractAdvice.java
@@ -20,6 +20,7 @@ import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.ValidationException;
+import org.apache.camel.processor.transformer.TypeConverterTransformer;
import org.apache.camel.spi.CamelInternalProcessorAdvice;
import org.apache.camel.spi.Contract;
import org.apache.camel.spi.DataType;
@@ -48,7 +49,7 @@ import org.slf4j.LoggerFactory;
public class ContractAdvice implements CamelInternalProcessorAdvice {
private static final Logger LOG = LoggerFactory.getLogger(ContractAdvice.class);
- private Contract contract;
+ private final Contract contract;
public ContractAdvice(Contract contract) {
this.contract = contract;
@@ -117,7 +118,7 @@ public class ContractAdvice implements CamelInternalProcessorAdvice {
private void doTransform(Message message, DataType from, DataType to) throws Exception {
if (from == null) {
- // If 'from' is null, only Java-Java convertion is performed.
+ // If 'from' is null, only Java-Java conversion is performed.
// It means if 'to' is other than Java, it's assumed to be already in expected type.
convertIfRequired(message, to);
return;
@@ -127,7 +128,7 @@ public class ContractAdvice implements CamelInternalProcessorAdvice {
convertIfRequired(message, from);
if (applyMatchedTransformer(message, from, to)) {
- // Found matched transformer. Java-Java transformer is also allowed.
+ // Found matched transformer. Java->Java transformer is also allowed.
return;
} else if (from.isJavaType()) {
// Try TypeConverter as a fallback for Java->Java transformation
@@ -143,39 +144,35 @@ public class ContractAdvice implements CamelInternalProcessorAdvice {
throw new IllegalArgumentException("No Transformer found for [from='" + from + "', to='" + to + "']");
}
- private boolean convertIfRequired(Message message, DataType type) throws Exception {
- // TODO for better performance it may be better to add TypeConverterTransformer
- // into transformer registry automatically to avoid unnecessary scan in transformer registry
- if (type != null && type.isJavaType() && type.getName() != null && message != null && message.getBody() != null) {
- CamelContext context = message.getExchange().getContext();
- Class<?> typeJava = getClazz(type.getName(), context);
- if (!typeJava.isAssignableFrom(message.getBody().getClass())) {
- LOG.debug("Converting to '{}'", typeJava.getName());
- message.setBody(message.getMandatoryBody(typeJava));
- return true;
- }
+ private void convertIfRequired(Message message, DataType type) throws Exception {
+ if (DataType.isAnyType(type) || !DataType.isJavaType(type) || type.getName() == null) {
+ return;
}
- return false;
- }
- private boolean applyTransformer(Transformer transformer, Message message, DataType from, DataType to) throws Exception {
+ CamelContext context = message.getExchange().getContext();
+ Transformer transformer = context.resolveTransformer(DataType.ANY, type);
if (transformer != null) {
- LOG.debug("Applying transformer: from='{}', to='{}', transformer='{}'", from, to, transformer);
- transformer.transform(message, from, to);
- return true;
+ transformer.transform(message, DataType.ANY, type);
+ } else {
+ new TypeConverterTransformer(type).transform(message, DataType.ANY, type);
}
- return false;
}
private boolean applyMatchedTransformer(Message message, DataType from, DataType to) throws Exception {
Transformer transformer = message.getExchange().getContext().resolveTransformer(from, to);
- return applyTransformer(transformer, message, from, to);
+ if (transformer == null) {
+ return false;
+ }
+
+ LOG.debug("Applying transformer: from='{}', to='{}', transformer='{}'", from, to, transformer);
+ transformer.transform(message, from, to);
+ return true;
}
private boolean applyTransformerChain(Message message, DataType from, DataType to) throws Exception {
CamelContext context = message.getExchange().getContext();
- Transformer fromTransformer = context.resolveTransformer(from.getModel());
- Transformer toTransformer = context.resolveTransformer(to.getModel());
+ Transformer fromTransformer = context.resolveTransformer(DataType.ANY, from);
+ Transformer toTransformer = context.resolveTransformer(DataType.ANY, to);
if (fromTransformer != null && toTransformer != null) {
LOG.debug("Applying transformer 1/2: from='{}', to='{}', transformer='{}'", from, to, fromTransformer);
fromTransformer.transform(message, from, new DataType(Object.class));
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/AnnotationTransformerLoader.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/AnnotationTransformerLoader.java
new file mode 100644
index 00000000000..77b23515cc8
--- /dev/null
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/AnnotationTransformerLoader.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.processor.transformer;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.ExtendedCamelContext;
+import org.apache.camel.Message;
+import org.apache.camel.TypeConverterLoaderException;
+import org.apache.camel.impl.engine.DefaultPackageScanClassResolver;
+import org.apache.camel.impl.engine.TransformerKey;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.PackageScanClassResolver;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.spi.TransformerLoader;
+import org.apache.camel.spi.TransformerRegistry;
+import org.apache.camel.support.PluginHelper;
+import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Transformer loader scans packages for {@link org.apache.camel.spi.Transformer} classes annotated with
+ * {@link DataType} annotation.
+ */
+public class AnnotationTransformerLoader extends Transformer implements TransformerLoader, CamelContextAware {
+
+ public static final String META_INF_SERVICES = "META-INF/services/org/apache/camel/Transformer";
+
+ private static final Logger LOG = LoggerFactory.getLogger(AnnotationTransformerLoader.class);
+
+ private CamelContext camelContext;
+
+ private String packageName;
+
+ private PackageScanClassResolver resolver;
+
+ private final Set<Class<?>> visitedClasses = new HashSet<>();
+ private final Set<String> visitedURIs = new HashSet<>();
+
+ @Override
+ public void load(TransformerRegistry registry) {
+ ObjectHelper.notNull(camelContext, "camelContext");
+
+ if (resolver == null) {
+ if (camelContext instanceof ExtendedCamelContext) {
+ resolver = PluginHelper.getPackageScanClassResolver(camelContext);
+ } else {
+ resolver = new DefaultPackageScanClassResolver();
+ }
+ }
+
+ Set<String> packages = new HashSet<>();
+
+ if (packageName == null || packageName.equals("*")) {
+ LOG.trace("Searching for {} services", META_INF_SERVICES);
+ try {
+ ClassLoader ccl = Thread.currentThread().getContextClassLoader();
+ if (ccl != null) {
+ findPackages(packages, ccl);
+ }
+ findPackages(packages, getClass().getClassLoader());
+ if (packages.isEmpty()) {
+ LOG.debug("No package names found to be used for classpath scanning for annotated data types.");
+ return;
+ }
+ } catch (Exception e) {
+ throw new TypeConverterLoaderException(
+ "Cannot find package names to be used for classpath scanning for annotated data types.", e);
+ }
+ } else {
+ packages.add(packageName);
+ }
+
+ // scan packages and load annotated transformer classes
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Found data type packages to scan: {}", String.join(", ", packages));
+ }
+ Set<Class<?>> scannedClasses = resolver.findAnnotated(DataTypeTransformer.class, packages.toArray(new String[] {}));
+ if (!scannedClasses.isEmpty()) {
+ LOG.debug("Found {} packages with {} @DataType classes to load", packages.size(), scannedClasses.size());
+
+ // load all the found classes into the type data type registry
+ for (Class<?> type : scannedClasses) {
+ if (acceptClass(type)) {
+ if (LOG.isTraceEnabled()) {
+ LOG.trace("Loading data type annotation: {}", ObjectHelper.name(type));
+ }
+ registerTransformer(registry, type);
+ }
+ }
+ }
+
+ // now clear the maps so we do not hold references
+ visitedClasses.clear();
+ visitedURIs.clear();
+ }
+
+ private void registerTransformer(TransformerRegistry registry, Class<?> type) {
+ if (visitedClasses.contains(type)) {
+ return;
+ }
+ visitedClasses.add(type);
+
+ try {
+ if (Transformer.class.isAssignableFrom(type) && type.isAnnotationPresent(DataTypeTransformer.class)) {
+ DataTypeTransformer dt = type.getAnnotation(DataTypeTransformer.class);
+ Transformer transformer = (Transformer) camelContext.getInjector().newInstance(type);
+ if (!ObjectHelper.isEmpty(dt.name())) {
+ registry.put(new TransformerKey(dt.name()), transformer);
+ }
+
+ if (!DataType.isAnyType(new DataType(dt.fromType())) || !DataType.isAnyType(new DataType(dt.toType()))) {
+ registry.put(new TransformerKey(new DataType(dt.fromType()), new DataType(dt.toType())), transformer);
+ }
+ }
+ } catch (NoClassDefFoundError e) {
+ LOG.debug("Ignoring transformer type: {} as a dependent class could not be found: {}",
+ type.getCanonicalName(), e, e);
+ }
+ }
+
+ protected boolean acceptClass(Class<?> type) {
+ return Transformer.class.isAssignableFrom(type) && type.isAnnotationPresent(DataTypeTransformer.class);
+ }
+
+ protected void findPackages(Set<String> packages, ClassLoader classLoader) throws IOException {
+ Enumeration<URL> resources = classLoader.getResources(META_INF_SERVICES);
+ while (resources.hasMoreElements()) {
+ URL url = resources.nextElement();
+ String path = url.getPath();
+ if (!visitedURIs.contains(path)) {
+ // remember we have visited this uri so we wont read it twice
+ visitedURIs.add(path);
+ LOG.debug("Loading file {} to retrieve list of packages, from url: {}", META_INF_SERVICES, url);
+ try (BufferedReader reader
+ = IOHelper.buffered(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8))) {
+ while (true) {
+ String line = reader.readLine();
+ if (line == null) {
+ break;
+ }
+ line = line.trim();
+ if (line.startsWith("#") || line.length() == 0) {
+ continue;
+ }
+ packages.add(line);
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void transform(Message message, DataType from, DataType to) throws Exception {
+ // noop
+ }
+
+ public void setPackageName(String packageName) {
+ this.packageName = packageName;
+ }
+
+ @Override
+ public void setCamelContext(CamelContext camelContext) {
+ this.camelContext = camelContext;
+ }
+
+ @Override
+ public CamelContext getCamelContext() {
+ return camelContext;
+ }
+}
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/TransformReifier.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/ByteArrayDataTypeTransformer.java
similarity index 50%
copy from core/camel-core-reifier/src/main/java/org/apache/camel/reifier/TransformReifier.java
copy to core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/ByteArrayDataTypeTransformer.java
index 4f7c4e1069e..d553d979ea1 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/TransformReifier.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/ByteArrayDataTypeTransformer.java
@@ -14,24 +14,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.reifier;
-import org.apache.camel.Expression;
-import org.apache.camel.Processor;
-import org.apache.camel.Route;
-import org.apache.camel.model.ProcessorDefinition;
-import org.apache.camel.model.TransformDefinition;
-import org.apache.camel.processor.TransformProcessor;
+package org.apache.camel.processor.transformer;
-public class TransformReifier extends ExpressionReifier<TransformDefinition> {
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
- public TransformReifier(Route route, ProcessorDefinition<?> definition) {
- super(route, (TransformDefinition) definition);
- }
+/**
+ * Generic binary data type uses Camel message body converter mechanism to convert content to byte array representation.
+ */
+@DataTypeTransformer(name = "application-octet-stream")
+public class ByteArrayDataTypeTransformer extends Transformer {
+
+ private static final Transformer DELEGATE = new TypeConverterTransformer(byte[].class);
@Override
- public Processor createProcessor() throws Exception {
- Expression expr = createExpression(definition.getExpression());
- return new TransformProcessor(expr);
+ public void transform(Message message, DataType from, DataType to) throws Exception {
+ DELEGATE.transform(message, from, to);
+
+ message.setHeader(Exchange.CONTENT_TYPE, "application/octet-stream");
}
}
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataFormatTransformer.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataFormatTransformer.java
index 64afbf8f78a..7e197d7c942 100644
--- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataFormatTransformer.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataFormatTransformer.java
@@ -42,6 +42,9 @@ public class DataFormatTransformer extends Transformer {
private DataFormat dataFormat;
private String transformerString;
+ public DataFormatTransformer() {
+ }
+
public DataFormatTransformer(CamelContext context) {
setCamelContext(context);
}
@@ -59,10 +62,10 @@ public class DataFormatTransformer extends Transformer {
CamelContext context = exchange.getContext();
// Unmarshaling into Java Object
- if ((to == null || to.isJavaType()) && (from.equals(getFrom()) || from.getModel().equals(getModel()))) {
+ if ((DataType.isAnyType(to) || to.isJavaType()) && (from.equals(getFrom()) || from.getScheme().equals(getName()))) {
LOG.debug("Unmarshaling with: {}", dataFormat);
Object answer = dataFormat.unmarshal(exchange, message.getBody(InputStream.class));
- if (to != null && to.getName() != null) {
+ if (!DataType.isAnyType(to) && to.getName() != null) {
Class<?> toClass = context.getClassResolver().resolveClass(to.getName());
if (!toClass.isAssignableFrom(answer.getClass())) {
LOG.debug("Converting to: {}", toClass.getName());
@@ -72,9 +75,10 @@ public class DataFormatTransformer extends Transformer {
message.setBody(answer);
// Marshaling from Java Object
- } else if ((from == null || from.isJavaType()) && (to.equals(getTo()) || to.getModel().equals(getModel()))) {
+ } else if ((DataType.isAnyType(from) || from.isJavaType())
+ && (to.equals(getTo()) || to.getScheme().equals(getName()))) {
Object input = message.getBody();
- if (from != null && from.getName() != null) {
+ if (!DataType.isAnyType(from) && from.getName() != null) {
Class<?> fromClass = context.getClassResolver().resolveClass(from.getName());
if (!fromClass.isAssignableFrom(input.getClass())) {
LOG.debug("Converting to: {}", fromClass.getName());
@@ -105,8 +109,8 @@ public class DataFormatTransformer extends Transformer {
@Override
public String toString() {
if (transformerString == null) {
- transformerString = String.format("DataFormatTransformer[scheme='%s', from='%s', to='%s', dataFormat='%s']",
- getModel(), getFrom(), getTo(), dataFormat);
+ transformerString = String.format("DataFormatTransformer[name='%s', from='%s', to='%s', dataFormat='%s']",
+ getName(), getFrom(), getTo(), dataFormat);
}
return transformerString;
}
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataTypeProcessor.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataTypeProcessor.java
new file mode 100644
index 00000000000..a7f9212bead
--- /dev/null
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DataTypeProcessor.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.processor.transformer;
+
+import java.util.Optional;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.Processor;
+import org.apache.camel.impl.engine.TransformerKey;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeAware;
+import org.apache.camel.spi.Transformer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Processor applies data type conversion based on given format name. Searches for matching data type transformer in
+ * context and applies its logic.
+ */
+public class DataTypeProcessor implements Processor {
+
+ public static final String DATA_TYPE_PROPERTY = "CamelDataType";
+
+ private static final Logger LOG = LoggerFactory.getLogger(DataTypeProcessor.class);
+
+ private String fromType;
+ private String toType;
+
+ private boolean ignoreMissingDataType;
+
+ private Transformer transformer;
+
+ public DataTypeProcessor() {
+ }
+
+ public DataTypeProcessor(String fromType, String toType) {
+ this.fromType = fromType;
+ this.toType = toType;
+ }
+
+ @Override
+ public void process(Exchange exchange) throws Exception {
+ if (toType == null && exchange.hasProperties() && exchange.getProperties().containsKey(DATA_TYPE_PROPERTY)) {
+ toType = exchange.getProperty(DATA_TYPE_PROPERTY, String.class);
+ }
+
+ if (toType == null || toType.isEmpty()) {
+ return;
+ }
+
+ Message message = exchange.getMessage();
+
+ DataType toDataType = new DataType(toType);
+ DataType fromDataType = DataType.ANY;
+ if (fromType != null) {
+ fromDataType = new DataType(fromType);
+ } else if (message instanceof DataTypeAware) {
+ fromDataType = ((DataTypeAware) message).getDataType();
+ }
+
+ Optional<Transformer> dataTypeTransformer = doLookupTransformer(exchange.getContext(), fromDataType, toDataType);
+ if (dataTypeTransformer.isPresent()) {
+ dataTypeTransformer.get().transform(message, fromDataType, toDataType);
+ } else if (ignoreMissingDataType) {
+ LOG.debug("Unable to find data type transformer from {} to type {}", fromDataType, toDataType);
+ } else {
+ throw new CamelExecutionException(
+ String.format("Missing data type transformer from %s to type %s", fromDataType, toDataType), exchange);
+ }
+ }
+
+ private Optional<Transformer> doLookupTransformer(CamelContext context, DataType fromType, DataType toType) {
+ if (transformer != null) {
+ return Optional.of(transformer);
+ }
+
+ Transformer maybeTransformer
+ = context.getTransformerRegistry().resolveTransformer(new TransformerKey(fromType, toType));
+ if (maybeTransformer != null) {
+ this.transformer = maybeTransformer;
+ return Optional.of(maybeTransformer);
+ }
+
+ return Optional.empty();
+ }
+
+ public void setFromType(String fromType) {
+ this.fromType = fromType;
+ }
+
+ public void setToType(String toType) {
+ this.toType = toType;
+ }
+
+ public void setTransformer(Transformer transformer) {
+ this.transformer = transformer;
+ }
+
+ public void setIgnoreMissingDataType(boolean ignoreMissingDataType) {
+ this.ignoreMissingDataType = ignoreMissingDataType;
+ }
+}
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DefaultTransformerLoader.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DefaultTransformerLoader.java
new file mode 100644
index 00000000000..aaf8d6adcf4
--- /dev/null
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/DefaultTransformerLoader.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.processor.transformer;
+
+import org.apache.camel.Message;
+import org.apache.camel.impl.engine.TransformerKey;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.spi.TransformerLoader;
+import org.apache.camel.spi.TransformerRegistry;
+
+/**
+ * Transformer loader loads known default {@link Transformer} implementations.
+ */
+public class DefaultTransformerLoader extends Transformer implements TransformerLoader {
+
+ @Override
+ public void load(TransformerRegistry registry) {
+ Transformer[] defaultTransformers = new Transformer[] {
+ new ByteArrayDataTypeTransformer(),
+ new StringDataTypeTransformer()
+ };
+
+ for (Transformer defaultTransformer : defaultTransformers) {
+ registry.put(TransformerKey.createFrom(defaultTransformer), defaultTransformer);
+ }
+ }
+
+ @Override
+ public void transform(Message message, DataType from, DataType to) throws Exception {
+ // noop
+ }
+}
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/ProcessorTransformer.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/ProcessorTransformer.java
index 62455d9422f..e5ab53860e7 100644
--- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/ProcessorTransformer.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/ProcessorTransformer.java
@@ -40,6 +40,9 @@ public class ProcessorTransformer extends Transformer {
private Processor processor;
private String transformerString;
+ public ProcessorTransformer() {
+ }
+
public ProcessorTransformer(CamelContext context) {
setCamelContext(context);
}
@@ -101,8 +104,8 @@ public class ProcessorTransformer extends Transformer {
@Override
public String toString() {
if (transformerString == null) {
- transformerString = String.format("ProcessorTransformer[scheme='%s', from='%s', to='%s', processor='%s']",
- getModel(), getFrom(), getTo(), processor);
+ transformerString = String.format("ProcessorTransformer[name='%s', from='%s', to='%s', processor='%s']",
+ getName(), getFrom(), getTo(), processor);
}
return transformerString;
}
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/StringDataTypeTransformer.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/StringDataTypeTransformer.java
new file mode 100644
index 00000000000..02e53b2a06b
--- /dev/null
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/StringDataTypeTransformer.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.processor.transformer;
+
+import java.nio.charset.StandardCharsets;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePropertyKey;
+import org.apache.camel.Message;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
+
+/**
+ * Generic String data type converts Exchange payload to String representation using the Camel message body converter
+ * mechanism. By default, uses UTF-8 charset as encoding.
+ */
+@DataTypeTransformer(name = "text-plain")
+public class StringDataTypeTransformer extends Transformer {
+
+ private static final Transformer DELEGATE = new TypeConverterTransformer(String.class);
+
+ @Override
+ public void transform(Message message, DataType from, DataType to) throws Exception {
+ message.getExchange().setProperty(ExchangePropertyKey.CHARSET_NAME, StandardCharsets.UTF_8.name());
+
+ DELEGATE.transform(message, from, to);
+
+ message.setHeader(Exchange.CONTENT_TYPE, "text/plain");
+ }
+}
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/TypeConverterTransformer.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/TypeConverterTransformer.java
new file mode 100644
index 00000000000..bbd7917a357
--- /dev/null
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/transformer/TypeConverterTransformer.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.processor.transformer;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.InvalidPayloadException;
+import org.apache.camel.Message;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Data type converter receives a name and a target type in order to use traditional exchange body conversion mechanisms
+ * in order to transform the message body to a given type.
+ */
+public class TypeConverterTransformer extends Transformer {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TypeConverterTransformer.class);
+
+ private DataType dataType;
+ private Class<?> type;
+
+ public TypeConverterTransformer(DataType type) {
+ super(type.getFullName());
+ this.dataType = type;
+ }
+
+ public TypeConverterTransformer(Class<?> type) {
+ super("java:" + type.getName());
+ this.type = type;
+ }
+
+ @Override
+ public void transform(Message message, DataType from, DataType to) {
+ if (message == null || message.getBody() == null) {
+ return;
+ }
+
+ try {
+ if (dataType != null) {
+ if (DataType.isJavaType(dataType) && dataType.getName() != null) {
+ CamelContext context = message.getExchange().getContext();
+ type = context.getClassResolver().resolveMandatoryClass(dataType.getName());
+ }
+ }
+
+ if (type != null && !type.isAssignableFrom(message.getBody().getClass())) {
+ LOG.debug("Converting to '{}'", type.getName());
+ message.setBody(message.getMandatoryBody(type));
+ }
+ } catch (InvalidPayloadException | ClassNotFoundException e) {
+ throw new CamelExecutionException(
+ String.format("Failed to convert body to '%s' content using type conversion for %s",
+ getName(), ObjectHelper.name(type)),
+ message.getExchange(), e);
+ }
+ }
+
+ public Class<?> getType() {
+ return type;
+ }
+}
diff --git a/core/camel-core-processor/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/application-octet-stream b/core/camel-core-processor/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/application-octet-stream
new file mode 100644
index 00000000000..6d209870e44
--- /dev/null
+++ b/core/camel-core-processor/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/application-octet-stream
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.processor.transformer.ByteArrayDataTypeTransformer
diff --git a/core/camel-core-processor/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/plain-text b/core/camel-core-processor/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/plain-text
new file mode 100644
index 00000000000..a2347583375
--- /dev/null
+++ b/core/camel-core-processor/src/main/resources/META-INF/services/org/apache/camel/datatype/transformer/plain-text
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.processor.transformer.StringDataTypeTransformer
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/TransformReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/TransformReifier.java
index 4f7c4e1069e..a8b7b41c55c 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/TransformReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/TransformReifier.java
@@ -22,6 +22,7 @@ import org.apache.camel.Route;
import org.apache.camel.model.ProcessorDefinition;
import org.apache.camel.model.TransformDefinition;
import org.apache.camel.processor.TransformProcessor;
+import org.apache.camel.processor.transformer.DataTypeProcessor;
public class TransformReifier extends ExpressionReifier<TransformDefinition> {
@@ -31,6 +32,15 @@ public class TransformReifier extends ExpressionReifier<TransformDefinition> {
@Override
public Processor createProcessor() throws Exception {
+ if (definition.getExpression() != null && definition.getToType() != null) {
+ throw new IllegalArgumentException(
+ "Both expression and data type set on transform EIP - please choose only one of them");
+ }
+
+ if (definition.getToType() != null) {
+ return new DataTypeProcessor(definition.getFromType(), definition.getToType());
+ }
+
Expression expr = createExpression(definition.getExpression());
return new TransformProcessor(expr);
}
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/CustomTransformerReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/CustomTransformerReifier.java
index 26ed5f1839d..7ab18da7177 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/CustomTransformerReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/CustomTransformerReifier.java
@@ -39,7 +39,7 @@ public class CustomTransformerReifier extends TransformerReifier<CustomTransform
if (transformer == null) {
throw new IllegalArgumentException("Cannot find transformer with ref:" + definition.getRef());
}
- if (transformer.getModel() != null || transformer.getFrom() != null || transformer.getTo() != null) {
+ if (transformer.getName() != null || transformer.getFrom() != null || transformer.getTo() != null) {
throw new IllegalArgumentException(
String.format("Transformer '%s' is already in use. Please check if duplicate transformer exists.",
definition.getRef()));
@@ -53,7 +53,8 @@ public class CustomTransformerReifier extends TransformerReifier<CustomTransform
transformer = camelContext.getInjector().newInstance(transformerClass, false);
}
transformer.setCamelContext(camelContext);
- return transformer.setModel(definition.getScheme()).setFrom(definition.getFromType()).setTo(definition.getToType());
+ return transformer.setName(definition.getScheme(), definition.getName()).setFrom(definition.getFromType())
+ .setTo(definition.getToType());
}
}
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/DataFormatTransformerReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/DataFormatTransformerReifier.java
index 294a5c5ea29..261f1db553c 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/DataFormatTransformerReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/DataFormatTransformerReifier.java
@@ -34,7 +34,8 @@ public class DataFormatTransformerReifier extends TransformerReifier<DataFormatT
protected Transformer doCreateTransformer() {
DataFormat dataFormat
= DataFormatReifier.getDataFormat(camelContext, definition.getDataFormatType());
- return new DataFormatTransformer(camelContext).setDataFormat(dataFormat).setModel(definition.getScheme())
+ return new DataFormatTransformer(camelContext).setDataFormat(dataFormat)
+ .setName(definition.getScheme(), definition.getName())
.setFrom(definition.getFromType()).setTo(definition.getToType());
}
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/EndpointTransformerReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/EndpointTransformerReifier.java
index 9877f41eee2..2afdcf20f4a 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/EndpointTransformerReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/EndpointTransformerReifier.java
@@ -38,7 +38,7 @@ public class EndpointTransformerReifier extends TransformerReifier<EndpointTrans
: lookupByNameAndType(parseString(definition.getRef()), Endpoint.class);
SendProcessor processor = new SendProcessor(endpoint, ExchangePattern.InOut);
return new ProcessorTransformer(camelContext).setProcessor(processor)
- .setModel(parseString(definition.getScheme()))
+ .setName(parseString(definition.getScheme()), parseString(definition.getName()))
.setFrom(parseString(definition.getFromType()))
.setTo(parseString(definition.getToType()));
}
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/DataFormatTransformerReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/LoadTransformerReifier.java
similarity index 53%
copy from core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/DataFormatTransformerReifier.java
copy to core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/LoadTransformerReifier.java
index 294a5c5ea29..14a90802b30 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/DataFormatTransformerReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/LoadTransformerReifier.java
@@ -17,25 +17,28 @@
package org.apache.camel.reifier.transformer;
import org.apache.camel.CamelContext;
-import org.apache.camel.model.transformer.DataFormatTransformerDefinition;
+import org.apache.camel.model.transformer.LoadTransformerDefinition;
import org.apache.camel.model.transformer.TransformerDefinition;
-import org.apache.camel.processor.transformer.DataFormatTransformer;
-import org.apache.camel.reifier.dataformat.DataFormatReifier;
-import org.apache.camel.spi.DataFormat;
+import org.apache.camel.processor.transformer.AnnotationTransformerLoader;
+import org.apache.camel.processor.transformer.DefaultTransformerLoader;
import org.apache.camel.spi.Transformer;
-public class DataFormatTransformerReifier extends TransformerReifier<DataFormatTransformerDefinition> {
+public class LoadTransformerReifier extends TransformerReifier<LoadTransformerDefinition> {
- public DataFormatTransformerReifier(CamelContext camelContext, TransformerDefinition definition) {
- super(camelContext, (DataFormatTransformerDefinition) definition);
+ public LoadTransformerReifier(CamelContext camelContext, TransformerDefinition definition) {
+ super(camelContext, (LoadTransformerDefinition) definition);
}
@Override
protected Transformer doCreateTransformer() {
- DataFormat dataFormat
- = DataFormatReifier.getDataFormat(camelContext, definition.getDataFormatType());
- return new DataFormatTransformer(camelContext).setDataFormat(dataFormat).setModel(definition.getScheme())
- .setFrom(definition.getFromType()).setTo(definition.getToType());
+ if (definition.getDefaults() != null && parseBoolean(definition.getDefaults(), false)) {
+ return new DefaultTransformerLoader();
+ } else {
+ AnnotationTransformerLoader transformerLoader = new AnnotationTransformerLoader();
+ transformerLoader.setCamelContext(camelContext);
+ transformerLoader.setPackageName(definition.getPackageScan());
+ return transformerLoader;
+ }
}
}
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/TransformerReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/TransformerReifier.java
index 63707ea4eaa..69a61a1ffc3 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/TransformerReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/transformer/TransformerReifier.java
@@ -24,6 +24,7 @@ import org.apache.camel.CamelContext;
import org.apache.camel.model.transformer.CustomTransformerDefinition;
import org.apache.camel.model.transformer.DataFormatTransformerDefinition;
import org.apache.camel.model.transformer.EndpointTransformerDefinition;
+import org.apache.camel.model.transformer.LoadTransformerDefinition;
import org.apache.camel.model.transformer.TransformerDefinition;
import org.apache.camel.reifier.AbstractReifier;
import org.apache.camel.spi.ReifierStrategy;
@@ -80,6 +81,8 @@ public abstract class TransformerReifier<T> extends AbstractReifier {
return new DataFormatTransformerReifier(camelContext, definition);
} else if (definition instanceof EndpointTransformerDefinition) {
return new EndpointTransformerReifier(camelContext, definition);
+ } else if (definition instanceof LoadTransformerDefinition) {
+ return new LoadTransformerReifier(camelContext, definition);
}
return null;
}
diff --git a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
index 92a0d7963ca..fb2662db6b5 100644
--- a/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
+++ b/core/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java
@@ -577,9 +577,15 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex
}
private static ValueHolder<String> createTransformerKey(TransformerDefinition def) {
- return org.apache.camel.util.ObjectHelper.isNotEmpty(def.getScheme())
- ? new TransformerKey(def.getScheme())
- : new TransformerKey(new DataType(def.getFromType()), new DataType(def.getToType()));
+ if (org.apache.camel.util.ObjectHelper.isNotEmpty(def.getScheme())) {
+ return org.apache.camel.util.ObjectHelper.isNotEmpty(def.getName())
+ ? new TransformerKey(def.getScheme() + ":" + def.getName()) : new TransformerKey(def.getScheme());
+ }
+ if (org.apache.camel.util.ObjectHelper.isNotEmpty(def.getName())) {
+ return new TransformerKey(def.getName());
+ } else {
+ return new TransformerKey(new DataType(def.getFromType()), new DataType(def.getToType()));
+ }
}
private void initValidators() {
diff --git a/core/camel-core/src/test/java/org/apache/camel/builder/TransformerBuilderTest.java b/core/camel-core/src/test/java/org/apache/camel/builder/TransformerBuilderTest.java
index 38e34f17476..338d32dbfe2 100644
--- a/core/camel-core/src/test/java/org/apache/camel/builder/TransformerBuilderTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/builder/TransformerBuilderTest.java
@@ -63,7 +63,7 @@ public class TransformerBuilderTest extends TestSupport {
RouteBuilder builder = new RouteBuilder() {
@Override
public void configure() throws Exception {
- transformer().scheme("other").withJava(MyTransformer.class);
+ transformer().name("other").withJava(MyTransformer.class);
from("direct:input").log("test");
}
};
diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultTransformerRegistryTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultTransformerRegistryTest.java
new file mode 100644
index 00000000000..a7de0a24a40
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultTransformerRegistryTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.impl.engine;
+
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.processor.transformer.ByteArrayDataTypeTransformer;
+import org.apache.camel.processor.transformer.StringDataTypeTransformer;
+import org.apache.camel.spi.Transformer;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class DefaultTransformerRegistryTest {
+
+ private final DefaultTransformerRegistry dataTypeRegistry = new DefaultTransformerRegistry(new DefaultCamelContext());
+
+ @Test
+ public void shouldLookupDefaultDataTypeConverters() throws Exception {
+ Transformer transformer = dataTypeRegistry.resolveTransformer(new TransformerKey("plain-text"));
+ Assertions.assertNotNull(transformer);
+ Assertions.assertEquals(StringDataTypeTransformer.class, transformer.getClass());
+ transformer = dataTypeRegistry.resolveTransformer(new TransformerKey("application-octet-stream"));
+ Assertions.assertNotNull(transformer);
+ Assertions.assertEquals(ByteArrayDataTypeTransformer.class, transformer.getClass());
+ transformer = dataTypeRegistry.resolveTransformer(new TransformerKey("lowercase"));
+ Assertions.assertNotNull(transformer);
+ Assertions.assertEquals(LowercaseDataTypeTransformer.class, transformer.getClass());
+ transformer = dataTypeRegistry.resolveTransformer(new TransformerKey("uppercase"));
+ Assertions.assertNotNull(transformer);
+ Assertions.assertEquals(UppercaseDataTypeTransformer.class, transformer.getClass());
+ }
+
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultTransformerResolverTest.java b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultTransformerResolverTest.java
new file mode 100644
index 00000000000..b7b17d9d354
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultTransformerResolverTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.impl.engine;
+
+import org.apache.camel.Message;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.processor.transformer.StringDataTypeTransformer;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class DefaultTransformerResolverTest {
+
+ private DefaultCamelContext camelContext;
+
+ private final DefaultTransformerResolver resolver = new DefaultTransformerResolver();
+
+ @BeforeEach
+ void setup() {
+ this.camelContext = new DefaultCamelContext();
+ }
+
+ @Test
+ public void shouldHandleUnresolvableDataTypeTransformers() throws Exception {
+ Transformer transformer = resolver.resolve(new TransformerKey("unknown"), camelContext);
+ Assertions.assertNull(transformer);
+
+ transformer = resolver.resolve(new TransformerKey(
+ new DataType("foo:fromType"),
+ new DataType("foo:toType")), camelContext);
+ Assertions.assertNull(transformer);
+ }
+
+ @Test
+ public void shouldResolveDataTypeTransformers() throws Exception {
+ Transformer transformer = resolver.resolve(new TransformerKey("plain-text"), camelContext);
+ Assertions.assertNotNull(transformer);
+ Assertions.assertEquals(StringDataTypeTransformer.class, transformer.getClass());
+
+ transformer = resolver.resolve(new TransformerKey("lowercase"), camelContext);
+ Assertions.assertNotNull(transformer);
+ Assertions.assertEquals(LowercaseDataTypeTransformer.class, transformer.getClass());
+
+ transformer = resolver.resolve(new TransformerKey(new DataType("foo"), new DataType("json")), camelContext);
+ Assertions.assertNotNull(transformer);
+ Assertions.assertEquals(FooDataTypeTransformer.class, transformer.getClass());
+ }
+
+ @DataTypeTransformer(name = "foo-json", fromType = "foo", toType = "json")
+ public static class FooDataTypeTransformer extends Transformer {
+
+ @Override
+ public void transform(Message message, DataType fromType, DataType toType) {
+ message.setBody("Foo");
+ }
+ }
+}
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java b/core/camel-core/src/test/java/org/apache/camel/impl/engine/LowercaseDataTypeTransformer.java
similarity index 63%
copy from core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
copy to core/camel-core/src/test/java/org/apache/camel/impl/engine/LowercaseDataTypeTransformer.java
index 23827554acc..3cdf31ee232 100644
--- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/engine/LowercaseDataTypeTransformer.java
@@ -14,16 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.api.management.mbean;
-import org.apache.camel.api.management.ManagedAttribute;
+package org.apache.camel.impl.engine;
-public interface ManagedTransformMBean extends ManagedProcessorMBean {
+import org.apache.camel.Message;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
- @ManagedAttribute(description = "The language for the expression")
- String getExpressionLanguage();
-
- @ManagedAttribute(description = "Expression to return the transformed message body (the new message body to use)")
- String getExpression();
+@DataTypeTransformer(name = "lowercase")
+public class LowercaseDataTypeTransformer extends Transformer {
+ @Override
+ public void transform(Message message, DataType fromType, DataType toType) {
+ message.setBody(message.getBody(String.class).toLowerCase());
+ }
}
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java b/core/camel-core/src/test/java/org/apache/camel/impl/engine/UppercaseDataTypeTransformer.java
similarity index 63%
copy from core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
copy to core/camel-core/src/test/java/org/apache/camel/impl/engine/UppercaseDataTypeTransformer.java
index 23827554acc..58cdd93eca7 100644
--- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
+++ b/core/camel-core/src/test/java/org/apache/camel/impl/engine/UppercaseDataTypeTransformer.java
@@ -14,16 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.api.management.mbean;
-import org.apache.camel.api.management.ManagedAttribute;
+package org.apache.camel.impl.engine;
-public interface ManagedTransformMBean extends ManagedProcessorMBean {
+import org.apache.camel.Message;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
- @ManagedAttribute(description = "The language for the expression")
- String getExpressionLanguage();
-
- @ManagedAttribute(description = "Expression to return the transformed message body (the new message body to use)")
- String getExpression();
+@DataTypeTransformer(name = "uppercase")
+public class UppercaseDataTypeTransformer extends Transformer {
+ @Override
+ public void transform(Message message, DataType fromType, DataType toType) {
+ message.setBody(message.getBody(String.class).toUpperCase());
+ }
}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/TransformDataTypeProcessorTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/TransformDataTypeProcessorTest.java
new file mode 100644
index 00000000000..02ad6bec7ac
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/TransformDataTypeProcessorTest.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.processor;
+
+import org.apache.camel.Message;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+
+public class TransformDataTypeProcessorTest extends TransformViaDSLTest {
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ public void configure() {
+ transformer().name("myDataType").withJava(MyDataTypeTransformer.class);
+ // START SNIPPET: example
+ from("direct:start").transform(new DataType("myDataType")).to("mock:result");
+ // END SNIPPET: example
+ }
+ };
+ }
+
+ public static class MyDataTypeTransformer extends Transformer {
+
+ @Override
+ public void transform(Message message, DataType from, DataType to) throws Exception {
+ message.setBody(message.getBody(String.class) + " World!");
+ }
+ }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/transformer/ByteArrayDataTypeTransformerTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/ByteArrayDataTypeTransformerTest.java
new file mode 100644
index 00000000000..1f5f3011f24
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/ByteArrayDataTypeTransformerTest.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.processor.transformer;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.engine.DefaultTransformerRegistry;
+import org.apache.camel.impl.engine.TransformerKey;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class ByteArrayDataTypeTransformerTest {
+
+ private final DefaultCamelContext camelContext = new DefaultCamelContext();
+
+ private final ByteArrayDataTypeTransformer transformer = new ByteArrayDataTypeTransformer();
+
+ @Test
+ void shouldRetainBytesModel() throws Exception {
+ Exchange exchange = new DefaultExchange(camelContext);
+
+ exchange.getMessage().setHeader("file", "test.txt");
+ exchange.getMessage().setBody("Test".getBytes(StandardCharsets.UTF_8));
+ transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+ Assertions.assertTrue(exchange.getMessage().hasHeaders());
+ assertBinaryBody(exchange, "test.txt", "Test");
+ }
+
+ @Test
+ void shouldTransformFromStringToBytesModel() throws Exception {
+ Exchange exchange = new DefaultExchange(camelContext);
+
+ exchange.getMessage().setHeader("file", "test1.txt");
+ exchange.getMessage().setBody("Test1");
+ transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+ Assertions.assertTrue(exchange.getMessage().hasHeaders());
+ assertBinaryBody(exchange, "test1.txt", "Test1");
+ }
+
+ @Test
+ void shouldTransformFromBytesToBytesModel() throws Exception {
+ Exchange exchange = new DefaultExchange(camelContext);
+
+ exchange.getMessage().setHeader("file", "test2.txt");
+ exchange.getMessage().setBody("Test2".getBytes(StandardCharsets.UTF_8));
+ transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+ Assertions.assertTrue(exchange.getMessage().hasHeaders());
+ assertBinaryBody(exchange, "test2.txt", "Test2");
+ }
+
+ @Test
+ void shouldTransformFromInputStreamToBytesModel() throws Exception {
+ Exchange exchange = new DefaultExchange(camelContext);
+
+ exchange.getMessage().setHeader("file", "test3.txt");
+ exchange.getMessage().setBody(new ByteArrayInputStream("Test3".getBytes(StandardCharsets.UTF_8)));
+ transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+ Assertions.assertTrue(exchange.getMessage().hasHeaders());
+ assertBinaryBody(exchange, "test3.txt", "Test3");
+ }
+
+ @Test
+ public void shouldResolveTransformer() throws Exception {
+ DefaultTransformerRegistry transformerRegistry = new DefaultTransformerRegistry(camelContext);
+ Transformer transformer = transformerRegistry.resolveTransformer(new TransformerKey("application-octet-stream"));
+ Assertions.assertNotNull(transformer);
+ }
+
+ private static void assertBinaryBody(Exchange exchange, String key, String content) {
+ assertEquals(key, exchange.getMessage().getHeader("file"));
+
+ assertEquals(byte[].class, exchange.getMessage().getBody().getClass());
+ assertEquals(content, exchange.getMessage().getBody(String.class));
+ }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/transformer/DataTypeProcessorTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/DataTypeProcessorTest.java
new file mode 100644
index 00000000000..065e148f088
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/DataTypeProcessorTest.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.processor.transformer;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.Exchange;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class DataTypeProcessorTest {
+
+ private final DefaultCamelContext camelContext = new DefaultCamelContext();
+
+ private final DataTypeProcessor processor = new DataTypeProcessor();
+
+ @BeforeEach
+ void setup() {
+ CamelContextAware.trySetCamelContext(processor, camelContext);
+ }
+
+ @Test
+ public void shouldApplyDataTypeConverterFromAnnotationLookup() throws Exception {
+ Exchange exchange = new DefaultExchange(camelContext);
+
+ exchange.getMessage().setBody(new ByteArrayInputStream("Test".getBytes(StandardCharsets.UTF_8)));
+ processor.setToType("uppercase");
+ processor.process(exchange);
+
+ assertEquals(String.class, exchange.getMessage().getBody().getClass());
+ assertEquals("TEST", exchange.getMessage().getBody());
+ }
+
+ @Test
+ public void shouldApplyDataTypeConverterFromResourceLookup() throws Exception {
+ Exchange exchange = new DefaultExchange(camelContext);
+
+ exchange.getMessage().setBody(new ByteArrayInputStream("Test".getBytes(StandardCharsets.UTF_8)));
+ processor.setToType("lowercase");
+ processor.process(exchange);
+
+ assertEquals(String.class, exchange.getMessage().getBody().getClass());
+ assertEquals("test", exchange.getMessage().getBody());
+ }
+
+ @Test
+ public void shouldIgnoreUnknownDataType() throws Exception {
+ Exchange exchange = new DefaultExchange(camelContext);
+
+ exchange.getMessage().setBody(new ByteArrayInputStream("Test".getBytes(StandardCharsets.UTF_8)));
+ processor.setIgnoreMissingDataType(true);
+ processor.setToType("foo:unknown");
+ processor.process(exchange);
+
+ assertEquals(ByteArrayInputStream.class, exchange.getMessage().getBody().getClass());
+ assertEquals("Test", exchange.getMessage().getBody(String.class));
+ }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/transformer/StringDataTypeTransformerTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/StringDataTypeTransformerTest.java
new file mode 100644
index 00000000000..25b70416c06
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/StringDataTypeTransformerTest.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.processor.transformer;
+
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.impl.engine.DefaultTransformerRegistry;
+import org.apache.camel.impl.engine.TransformerKey;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class StringDataTypeTransformerTest {
+
+ private final DefaultCamelContext camelContext = new DefaultCamelContext();
+
+ private final StringDataTypeTransformer transformer = new StringDataTypeTransformer();
+
+ @Test
+ void shouldRetainStringModel() throws Exception {
+ Exchange exchange = new DefaultExchange(camelContext);
+
+ exchange.getMessage().setHeader("file", "test.txt");
+ exchange.getMessage().setBody("Test");
+ transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+ Assertions.assertTrue(exchange.getMessage().hasHeaders());
+ assertStringBody(exchange, "test.txt", "Test");
+ }
+
+ @Test
+ void shouldMapFromBinaryToStringModel() throws Exception {
+ Exchange exchange = new DefaultExchange(camelContext);
+
+ exchange.getMessage().setHeader("file", "test1.txt");
+ exchange.getMessage().setBody("Test1".getBytes(StandardCharsets.UTF_8));
+ transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+ Assertions.assertTrue(exchange.getMessage().hasHeaders());
+ assertStringBody(exchange, "test1.txt", "Test1");
+ }
+
+ @Test
+ void shouldMapFromInputStreamToStringModel() throws Exception {
+ Exchange exchange = new DefaultExchange(camelContext);
+
+ exchange.getMessage().setHeader("file", "test3.txt");
+ exchange.getMessage().setBody(new ByteArrayInputStream("Test3".getBytes(StandardCharsets.UTF_8)));
+ transformer.transform(exchange.getMessage(), DataType.ANY, DataType.ANY);
+
+ Assertions.assertTrue(exchange.getMessage().hasHeaders());
+ assertStringBody(exchange, "test3.txt", "Test3");
+ }
+
+ @Test
+ public void shouldLookupDataType() throws Exception {
+ DefaultTransformerRegistry dataTypeRegistry = new DefaultTransformerRegistry(camelContext);
+ Transformer transformer = dataTypeRegistry.resolveTransformer(new TransformerKey("plain-text"));
+ Assertions.assertNotNull(transformer);
+ }
+
+ private static void assertStringBody(Exchange exchange, String key, String content) {
+ assertEquals(key, exchange.getMessage().getHeader("file"));
+
+ assertEquals(String.class, exchange.getMessage().getBody().getClass());
+ assertEquals(content, exchange.getMessage().getBody(String.class));
+ }
+}
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/transformer/TransformerRouteTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/TransformerRouteTest.java
index 8a3f850300d..1fdf129e747 100644
--- a/core/camel-core/src/test/java/org/apache/camel/processor/transformer/TransformerRouteTest.java
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/TransformerRouteTest.java
@@ -64,7 +64,7 @@ public class TransformerRouteTest extends ContextTestSupport {
abcresult.whenAnyExchangeReceived(new Processor() {
@Override
public void process(Exchange exchange) throws Exception {
- LOG.info("Asserting String -> XOrderResponse convertion");
+ LOG.info("Asserting String -> XOrderResponse conversion");
assertEquals(XOrderResponse.class, exchange.getIn().getBody().getClass());
}
@@ -75,7 +75,7 @@ public class TransformerRouteTest extends ContextTestSupport {
xyzresult.whenAnyExchangeReceived(new Processor() {
@Override
public void process(Exchange exchange) throws Exception {
- LOG.info("Asserting String -> XOrderResponse convertion is not yet performed");
+ LOG.info("Asserting String -> XOrderResponse conversion is not yet performed");
assertEquals("response", exchange.getIn().getBody());
}
});
@@ -97,7 +97,7 @@ public class TransformerRouteTest extends ContextTestSupport {
xyzresult.whenAnyExchangeReceived(new Processor() {
@Override
public void process(Exchange exchange) throws Exception {
- LOG.info("Asserting String -> XOrderResponse convertion is not yet performed");
+ LOG.info("Asserting String -> XOrderResponse conversion is not yet performed");
assertEquals("response", exchange.getIn().getBody());
}
});
@@ -119,7 +119,7 @@ public class TransformerRouteTest extends ContextTestSupport {
xyzresult.whenAnyExchangeReceived(new Processor() {
@Override
public void process(Exchange exchange) throws Exception {
- LOG.info("Asserting String -> XOrderResponse convertion is not yet performed");
+ LOG.info("Asserting String -> XOrderResponse conversion is not yet performed");
assertEquals("response", exchange.getIn().getBody());
}
});
@@ -141,7 +141,7 @@ public class TransformerRouteTest extends ContextTestSupport {
xyzresult.whenAnyExchangeReceived(new Processor() {
@Override
public void process(Exchange exchange) throws Exception {
- LOG.info("Asserting String -> XOrderResponse convertion is not yet performed");
+ LOG.info("Asserting String -> XOrderResponse conversion is not yet performed");
assertEquals("response", exchange.getIn().getBody());
}
});
@@ -178,14 +178,14 @@ public class TransformerRouteTest extends ContextTestSupport {
context.getTypeConverterRegistry().addTypeConverters(new MyTypeConverters());
from("direct:abc").inputType(AOrder.class).outputType(AOrderResponse.class).process(new Processor() {
public void process(Exchange exchange) throws Exception {
- LOG.info("Asserting input -> AOrder convertion");
+ LOG.info("Asserting input -> AOrder conversion");
assertEquals(AOrder.class, exchange.getIn().getBody().getClass());
}
}).to(ExchangePattern.InOut, "direct:xyz").to("mock:abcresult");
from("direct:xyz").inputType(XOrder.class).outputType(XOrderResponse.class).process(new Processor() {
public void process(Exchange exchange) throws Exception {
- LOG.info("Asserting input -> XOrder convertion");
+ LOG.info("Asserting input -> XOrder conversion");
assertEquals(XOrder.class, exchange.getIn().getBody().getClass());
exchange.getIn().setBody("response");
}
@@ -206,12 +206,15 @@ public class TransformerRouteTest extends ContextTestSupport {
.withJava(XOrderResponseToOtherTransformer.class);
from("direct:custom").inputType("other:OtherXOrder").outputType("other:OtherXOrderResponse")
.to(ExchangePattern.InOut, "direct:xyz");
- transformer().scheme("myDataType").withDataFormat(new MyDataFormatDefinition());
+ transformer().name("myDataType").withDataFormat(new MyDataFormatDefinition());
from("direct:testDataType").inputTypeWithValidate("myDataType")
.to("direct:testDataTypeStep2");
from("direct:testDataTypeStep2").inputType(MyDataType.class)
.to("mock:testDataType");
validator().type("myDataType").withExpression(bodyAs(String.class).contains("fake"));
+
+ transformer().withDefaults();
+ transformer().scan("com.apache.camel.processor.transformer.custom");
}
};
}
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/custom/CustomDataTypeTransformer.java
similarity index 63%
copy from core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
copy to core/camel-core/src/test/java/org/apache/camel/processor/transformer/custom/CustomDataTypeTransformer.java
index 23827554acc..3dc9339c69e 100644
--- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/transformer/custom/CustomDataTypeTransformer.java
@@ -14,16 +14,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.api.management.mbean;
-import org.apache.camel.api.management.ManagedAttribute;
+package org.apache.camel.processor.transformer.custom;
-public interface ManagedTransformMBean extends ManagedProcessorMBean {
+import org.apache.camel.Message;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.DataTypeTransformer;
+import org.apache.camel.spi.Transformer;
- @ManagedAttribute(description = "The language for the expression")
- String getExpressionLanguage();
-
- @ManagedAttribute(description = "Expression to return the transformed message body (the new message body to use)")
- String getExpression();
+@DataTypeTransformer(name = "custom")
+public class CustomDataTypeTransformer extends Transformer {
+ @Override
+ public void transform(Message message, DataType from, DataType to) throws Exception {
+ message.setBody("customized");
+ }
}
diff --git a/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/foo-json b/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/foo-json
new file mode 100644
index 00000000000..9b2546f6062
--- /dev/null
+++ b/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/foo-json
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.impl.engine.DefaultTransformerResolverTest$FooDataTypeTransformer
diff --git a/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/lowercase b/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/lowercase
new file mode 100644
index 00000000000..0ee439ca63b
--- /dev/null
+++ b/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/lowercase
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.impl.engine.LowercaseDataTypeTransformer
diff --git a/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/uppercase b/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/uppercase
new file mode 100644
index 00000000000..734ff7f25ed
--- /dev/null
+++ b/core/camel-core/src/test/resources/META-INF/services/org/apache/camel/datatype/transformer/uppercase
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+class=org.apache.camel.impl.engine.UppercaseDataTypeTransformer
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java
index 991a0325d6f..93b01ebd60d 100644
--- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java
+++ b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/CamelOpenMBeanTypes.java
@@ -217,14 +217,14 @@ public final class CamelOpenMBeanTypes {
public static TabularType listTransformersTabularType() throws OpenDataException {
CompositeType ct = listTransformersCompositeType();
return new TabularType(
- "listTransformers", "Lists all the transformers in the registry", ct, new String[] { "scheme", "from", "to" });
+ "listTransformers", "Lists all the transformers in the registry", ct, new String[] { "name", "from", "to" });
}
public static CompositeType listTransformersCompositeType() throws OpenDataException {
return new CompositeType(
"transformers", "Transformers",
- new String[] { "scheme", "from", "to", "static", "dynamic", "description" },
- new String[] { "Scheme", "From", "To", "Static", "Dynamic", "Description" },
+ new String[] { "name", "from", "to", "static", "dynamic", "description" },
+ new String[] { "Name", "From", "To", "Static", "Dynamic", "Description" },
new OpenType[] {
SimpleType.STRING, SimpleType.STRING, SimpleType.STRING,
SimpleType.BOOLEAN, SimpleType.BOOLEAN, SimpleType.STRING });
diff --git a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
index 23827554acc..271319f9203 100644
--- a/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
+++ b/core/camel-management-api/src/main/java/org/apache/camel/api/management/mbean/ManagedTransformMBean.java
@@ -26,4 +26,10 @@ public interface ManagedTransformMBean extends ManagedProcessorMBean {
@ManagedAttribute(description = "Expression to return the transformed message body (the new message body to use)")
String getExpression();
+ @ManagedAttribute(description = "Data type used as defined input for the message transformation")
+ String getFromType();
+
+ @ManagedAttribute(description = "Data type representing the defined outcome of a data type transformation (the new message body to use)")
+ String getToType();
+
}
diff --git a/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementObjectStrategy.java b/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementObjectStrategy.java
index 2338ad1bc89..773573228aa 100644
--- a/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementObjectStrategy.java
+++ b/core/camel-management/src/main/java/org/apache/camel/management/DefaultManagementObjectStrategy.java
@@ -179,6 +179,7 @@ import org.apache.camel.processor.loadbalancer.RoundRobinLoadBalancer;
import org.apache.camel.processor.loadbalancer.StickyLoadBalancer;
import org.apache.camel.processor.loadbalancer.TopicLoadBalancer;
import org.apache.camel.processor.loadbalancer.WeightedLoadBalancer;
+import org.apache.camel.processor.transformer.DataTypeProcessor;
import org.apache.camel.spi.BrowsableEndpoint;
import org.apache.camel.spi.DataFormat;
import org.apache.camel.spi.ErrorHandler;
@@ -437,7 +438,9 @@ public class DefaultManagementObjectStrategy implements ManagementObjectStrategy
} else if (target instanceof ThrowExceptionProcessor) {
answer = new ManagedThrowException(context, (ThrowExceptionProcessor) target, definition);
} else if (target instanceof TransformProcessor) {
- answer = new ManagedTransformer(context, (TransformProcessor) target, (TransformDefinition) definition);
+ answer = new ManagedTransformer(context, target, (TransformDefinition) definition);
+ } else if (target instanceof DataTypeProcessor) {
+ answer = new ManagedTransformer(context, target, (TransformDefinition) definition);
} else if (target instanceof PredicateValidatingProcessor) {
answer = new ManagedValidate(context, (PredicateValidatingProcessor) target, (ValidateDefinition) definition);
} else if (target instanceof WireTapProcessor) {
diff --git a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTransformer.java b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTransformer.java
index 465387af416..00916eb866e 100644
--- a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTransformer.java
+++ b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTransformer.java
@@ -17,18 +17,16 @@
package org.apache.camel.management.mbean;
import org.apache.camel.CamelContext;
+import org.apache.camel.Processor;
import org.apache.camel.api.management.ManagedResource;
import org.apache.camel.api.management.mbean.ManagedTransformMBean;
import org.apache.camel.model.TransformDefinition;
-import org.apache.camel.processor.TransformProcessor;
@ManagedResource(description = "Managed Transformer")
public class ManagedTransformer extends ManagedProcessor implements ManagedTransformMBean {
- private final TransformProcessor processor;
- public ManagedTransformer(CamelContext context, TransformProcessor processor, TransformDefinition definition) {
+ public ManagedTransformer(CamelContext context, Processor processor, TransformDefinition definition) {
super(context, processor, definition);
- this.processor = processor;
}
@Override
@@ -45,4 +43,14 @@ public class ManagedTransformer extends ManagedProcessor implements ManagedTrans
public String getExpression() {
return getDefinition().getExpression().getExpression();
}
+
+ @Override
+ public String getFromType() {
+ return getDefinition().getFromType();
+ }
+
+ @Override
+ public String getToType() {
+ return getDefinition().getToType();
+ }
}
diff --git a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTransformerRegistry.java b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTransformerRegistry.java
index 8f9943f065f..79ac1ff8c3d 100644
--- a/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTransformerRegistry.java
+++ b/core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedTransformerRegistry.java
@@ -84,18 +84,18 @@ public class ManagedTransformerRegistry extends ManagedService implements Manage
Collection<Transformer> transformers = transformerRegistry.values();
for (Transformer transformer : transformers) {
CompositeType ct = CamelOpenMBeanTypes.listTransformersCompositeType();
- String scheme = transformer.getModel();
+ String name = transformer.getName();
DataType from = transformer.getFrom();
DataType to = transformer.getTo();
String desc = transformer.toString();
boolean fromStatic
- = scheme != null ? transformerRegistry.isStatic(scheme) : transformerRegistry.isStatic(from, to);
+ = name != null ? transformerRegistry.isStatic(name) : transformerRegistry.isStatic(from, to);
boolean fromDynamic
- = scheme != null ? transformerRegistry.isDynamic(scheme) : transformerRegistry.isDynamic(from, to);
+ = name != null ? transformerRegistry.isDynamic(name) : transformerRegistry.isDynamic(from, to);
CompositeData data = new CompositeDataSupport(
- ct, new String[] { "scheme", "from", "to", "static", "dynamic", "description" },
- new Object[] { scheme, from.toString(), to.toString(), fromStatic, fromDynamic, desc });
+ ct, new String[] { "name", "from", "to", "static", "dynamic", "description" },
+ new Object[] { name, from.toString(), to.toString(), fromStatic, fromDynamic, desc });
answer.put(data);
}
return answer;
diff --git a/core/camel-management/src/test/java/org/apache/camel/management/ManagedTransformerRegistryTest.java b/core/camel-management/src/test/java/org/apache/camel/management/ManagedTransformerRegistryTest.java
index 104bfdffe68..6d5f01dee05 100644
--- a/core/camel-management/src/test/java/org/apache/camel/management/ManagedTransformerRegistryTest.java
+++ b/core/camel-management/src/test/java/org/apache/camel/management/ManagedTransformerRegistryTest.java
@@ -85,25 +85,25 @@ public class ManagedTransformerRegistryTest extends ManagementTestSupport {
TabularData data = (TabularData) mbeanServer.invoke(on, "listTransformers", null, null);
for (Object row : data.values()) {
CompositeData composite = (CompositeData) row;
- String scheme = (String) composite.get("scheme");
+ String name = (String) composite.get("name");
String from = (String) composite.get("from");
String to = (String) composite.get("to");
String description = (String) composite.get("description");
boolean isStatic = (boolean) composite.get("static");
boolean isDynamic = (boolean) composite.get("dynamic");
- LOG.info("[{}][{}][{}][{}][{}][{}]", scheme, from, to, isStatic, isDynamic, description);
+ LOG.info("[{}][{}][{}][{}][{}][{}]", name, from, to, isStatic, isDynamic, description);
if (description.startsWith("ProcessorTransformer")) {
- assertEquals(null, scheme);
+ assertEquals(null, name);
assertEquals("xml:foo", from);
assertEquals("json:bar", to);
} else if (description.startsWith("DataFormatTransformer")) {
- assertEquals(null, scheme);
+ assertEquals(null, name);
assertEquals("java:" + ManagedTransformerRegistryTest.class.getName(), from);
assertEquals("xml:test", to);
} else if (description.startsWith("MyTransformer")) {
- assertEquals("custom", scheme);
- assertEquals(null, from);
- assertEquals(null, to);
+ assertEquals("custom", name);
+ assertEquals("camel:any", from);
+ assertEquals("camel:any", to);
} else {
fail("Unexpected transformer:" + description);
}
@@ -121,7 +121,7 @@ public class ManagedTransformerRegistryTest extends ManagementTestSupport {
.toType("json:bar")
.withUri("direct:transformer");
transformer()
- .scheme("custom")
+ .name("custom")
.withJava(MyTransformer.class);
from("direct:start").to("mock:result");
diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
index 3acd8f38740..1438223c20f 100644
--- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
+++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
@@ -1513,8 +1513,14 @@ public class ModelParser extends BaseParser {
}, outputDefinitionElementHandler(), noValueHandler());
}
protected TransformDefinition doParseTransformDefinition() throws IOException, XmlPullParserException {
- return doParse(new TransformDefinition(),
- processorDefinitionAttributeHandler(), expressionNodeElementHandler(), noValueHandler());
+ return doParse(new TransformDefinition(), (def, key, val) -> {
+ switch (key) {
+ case "fromType": def.setFromType(val); break;
+ case "toType": def.setToType(val); break;
+ default: return processorDefinitionAttributeHandler().accept(def, key, val);
+ }
+ return true;
+ }, expressionNodeElementHandler(), noValueHandler());
}
protected TryDefinition doParseTryDefinition() throws IOException, XmlPullParserException {
return doParse(new TryDefinition(),
@@ -3242,6 +3248,7 @@ public class ModelParser extends BaseParser {
return (def, key, val) -> {
switch (key) {
case "fromType": def.setFromType(val); break;
+ case "name": def.setName(val); break;
case "scheme": def.setScheme(val); break;
case "toType": def.setToType(val); break;
default: return false;
@@ -3270,12 +3277,23 @@ public class ModelParser extends BaseParser {
return true;
}, noElementHandler(), noValueHandler());
}
+ protected LoadTransformerDefinition doParseLoadTransformerDefinition() throws IOException, XmlPullParserException {
+ return doParse(new LoadTransformerDefinition(), (def, key, val) -> {
+ switch (key) {
+ case "defaults": def.setDefaults(val); break;
+ case "packageScan": def.setPackageScan(val); break;
+ default: return transformerDefinitionAttributeHandler().accept(def, key, val);
+ }
+ return true;
+ }, noElementHandler(), noValueHandler());
+ }
protected TransformersDefinition doParseTransformersDefinition() throws IOException, XmlPullParserException {
return doParse(new TransformersDefinition(),
noAttributeHandler(), (def, key) -> {
switch (key) {
case "dataFormatTransformer": doAdd(doParseDataFormatTransformerDefinition(), def.getTransformers(), def::setTransformers); break;
case "endpointTransformer": doAdd(doParseEndpointTransformerDefinition(), def.getTransformers(), def::setTransformers); break;
+ case "loadTransformer": doAdd(doParseLoadTransformerDefinition(), def.getTransformers(), def::setTransformers); break;
case "customTransformer": doAdd(doParseCustomTransformerDefinition(), def.getTransformers(), def::setTransformers); break;
default: return false;
}
diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
index 2104066297c..ea0520d9d52 100644
--- a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
+++ b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/out/ModelWriter.java
@@ -2381,6 +2381,8 @@ public class ModelWriter extends BaseWriter {
throws IOException {
startElement(name);
doWriteProcessorDefinitionAttributes(def);
+ doWriteAttribute("toType", def.getToType());
+ doWriteAttribute("fromType", def.getFromType());
doWriteExpressionNodeElements(def);
endElement(name);
}
@@ -4547,12 +4549,23 @@ public class ModelWriter extends BaseWriter {
doWriteAttribute("uri", def.getUri());
endElement(name);
}
+ protected void doWriteLoadTransformerDefinition(
+ String name,
+ LoadTransformerDefinition def)
+ throws IOException {
+ startElement(name);
+ doWriteTransformerDefinitionAttributes(def);
+ doWriteAttribute("defaults", def.getDefaults());
+ doWriteAttribute("packageScan", def.getPackageScan());
+ endElement(name);
+ }
protected void doWriteTransformerDefinitionAttributes(
TransformerDefinition def)
throws IOException {
doWriteAttribute("toType", def.getToType());
doWriteAttribute("fromType", def.getFromType());
doWriteAttribute("scheme", def.getScheme());
+ doWriteAttribute("name", def.getName());
}
protected void doWriteTransformerDefinition(
String name,
@@ -4571,6 +4584,7 @@ public class ModelWriter extends BaseWriter {
switch (v.getClass().getSimpleName()) {
case "DataFormatTransformerDefinition" -> doWriteDataFormatTransformerDefinition("dataFormatTransformer", (DataFormatTransformerDefinition) v);
case "EndpointTransformerDefinition" -> doWriteEndpointTransformerDefinition("endpointTransformer", (EndpointTransformerDefinition) v);
+ case "LoadTransformerDefinition" -> doWriteLoadTransformerDefinition("loadTransformer", (LoadTransformerDefinition) v);
case "CustomTransformerDefinition" -> doWriteCustomTransformerDefinition("customTransformer", (CustomTransformerDefinition) v);
}
});
diff --git a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
index 9b00f8064dc..b0d62b775d7 100644
--- a/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
+++ b/core/camel-yaml-io/src/generated/java/org/apache/camel/yaml/out/ModelWriter.java
@@ -2381,6 +2381,8 @@ public class ModelWriter extends BaseWriter {
throws IOException {
startElement(name);
doWriteProcessorDefinitionAttributes(def);
+ doWriteAttribute("toType", def.getToType());
+ doWriteAttribute("fromType", def.getFromType());
doWriteExpressionNodeElements(def);
endElement(name);
}
@@ -4547,12 +4549,23 @@ public class ModelWriter extends BaseWriter {
doWriteAttribute("uri", def.getUri());
endElement(name);
}
+ protected void doWriteLoadTransformerDefinition(
+ String name,
+ LoadTransformerDefinition def)
+ throws IOException {
+ startElement(name);
+ doWriteTransformerDefinitionAttributes(def);
+ doWriteAttribute("defaults", def.getDefaults());
+ doWriteAttribute("packageScan", def.getPackageScan());
+ endElement(name);
+ }
protected void doWriteTransformerDefinitionAttributes(
TransformerDefinition def)
throws IOException {
doWriteAttribute("toType", def.getToType());
doWriteAttribute("fromType", def.getFromType());
doWriteAttribute("scheme", def.getScheme());
+ doWriteAttribute("name", def.getName());
}
protected void doWriteTransformerDefinition(
String name,
@@ -4571,6 +4584,7 @@ public class ModelWriter extends BaseWriter {
switch (v.getClass().getSimpleName()) {
case "DataFormatTransformerDefinition" -> doWriteDataFormatTransformerDefinition("dataFormatTransformer", (DataFormatTransformerDefinition) v);
case "EndpointTransformerDefinition" -> doWriteEndpointTransformerDefinition("endpointTransformer", (EndpointTransformerDefinition) v);
+ case "LoadTransformerDefinition" -> doWriteLoadTransformerDefinition("loadTransformer", (LoadTransformerDefinition) v);
case "CustomTransformerDefinition" -> doWriteCustomTransformerDefinition("customTransformer", (CustomTransformerDefinition) v);
}
});
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
index 91b18829099..c0211030ffb 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializers.java
@@ -231,6 +231,7 @@ import org.apache.camel.model.rest.SecurityDefinition;
import org.apache.camel.model.transformer.CustomTransformerDefinition;
import org.apache.camel.model.transformer.DataFormatTransformerDefinition;
import org.apache.camel.model.transformer.EndpointTransformerDefinition;
+import org.apache.camel.model.transformer.LoadTransformerDefinition;
import org.apache.camel.model.transformer.TransformersDefinition;
import org.apache.camel.model.validator.CustomValidatorDefinition;
import org.apache.camel.model.validator.EndpointValidatorDefinition;
@@ -2999,6 +3000,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
properties = {
@YamlProperty(name = "class-name", type = "string"),
@YamlProperty(name = "from-type", type = "string"),
+ @YamlProperty(name = "name", type = "string"),
@YamlProperty(name = "ref", type = "string"),
@YamlProperty(name = "scheme", type = "string"),
@YamlProperty(name = "to-type", type = "string")
@@ -3028,6 +3030,11 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
target.setFromType(val);
break;
}
+ case "name": {
+ String val = asText(node);
+ target.setName(val);
+ break;
+ }
case "ref": {
String val = asText(node);
target.setRef(val);
@@ -3156,6 +3163,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
@YamlProperty(name = "json-api", type = "object:org.apache.camel.model.dataformat.JsonApiDataFormat"),
@YamlProperty(name = "lzf", type = "object:org.apache.camel.model.dataformat.LZFDataFormat"),
@YamlProperty(name = "mime-multipart", type = "object:org.apache.camel.model.dataformat.MimeMultipartDataFormat"),
+ @YamlProperty(name = "name", type = "string"),
@YamlProperty(name = "parquet-avro", type = "object:org.apache.camel.model.dataformat.ParquetAvroDataFormat"),
@YamlProperty(name = "pgp", type = "object:org.apache.camel.model.dataformat.PGPDataFormat"),
@YamlProperty(name = "protobuf", type = "object:org.apache.camel.model.dataformat.ProtobufDataFormat"),
@@ -3402,6 +3410,11 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
target.setFromType(val);
break;
}
+ case "name": {
+ String val = asText(node);
+ target.setName(val);
+ break;
+ }
case "scheme": {
String val = asText(node);
target.setScheme(val);
@@ -4623,6 +4636,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
order = org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1,
properties = {
@YamlProperty(name = "from-type", type = "string"),
+ @YamlProperty(name = "name", type = "string"),
@YamlProperty(name = "ref", type = "string"),
@YamlProperty(name = "scheme", type = "string"),
@YamlProperty(name = "to-type", type = "string"),
@@ -4648,6 +4662,11 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
target.setFromType(val);
break;
}
+ case "name": {
+ String val = asText(node);
+ target.setName(val);
+ break;
+ }
case "ref": {
String val = asText(node);
target.setRef(val);
@@ -8184,6 +8203,70 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
}
}
+ @YamlType(
+ types = org.apache.camel.model.transformer.LoadTransformerDefinition.class,
+ order = org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1,
+ properties = {
+ @YamlProperty(name = "defaults", type = "boolean"),
+ @YamlProperty(name = "from-type", type = "string"),
+ @YamlProperty(name = "name", type = "string"),
+ @YamlProperty(name = "package-scan", type = "string"),
+ @YamlProperty(name = "scheme", type = "string"),
+ @YamlProperty(name = "to-type", type = "string")
+ }
+ )
+ public static class LoadTransformerDefinitionDeserializer extends YamlDeserializerBase<LoadTransformerDefinition> {
+ public LoadTransformerDefinitionDeserializer() {
+ super(LoadTransformerDefinition.class);
+ }
+
+ @Override
+ protected LoadTransformerDefinition newInstance() {
+ return new LoadTransformerDefinition();
+ }
+
+ @Override
+ protected boolean setProperty(LoadTransformerDefinition target, String propertyKey,
+ String propertyName, Node node) {
+ switch(propertyKey) {
+ case "defaults": {
+ String val = asText(node);
+ target.setDefaults(val);
+ break;
+ }
+ case "from-type": {
+ String val = asText(node);
+ target.setFromType(val);
+ break;
+ }
+ case "name": {
+ String val = asText(node);
+ target.setName(val);
+ break;
+ }
+ case "package-scan": {
+ String val = asText(node);
+ target.setPackageScan(val);
+ break;
+ }
+ case "scheme": {
+ String val = asText(node);
+ target.setScheme(val);
+ break;
+ }
+ case "to-type": {
+ String val = asText(node);
+ target.setToType(val);
+ break;
+ }
+ default: {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
@YamlType(
nodes = "log",
inline = true,
@@ -17074,8 +17157,10 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
@YamlProperty(name = "description", type = "string"),
@YamlProperty(name = "disabled", type = "boolean"),
@YamlProperty(name = "expression", type = "object:org.apache.camel.model.language.ExpressionDefinition"),
+ @YamlProperty(name = "from-type", type = "string"),
@YamlProperty(name = "id", type = "string"),
- @YamlProperty(name = "inherit-error-handler", type = "boolean")
+ @YamlProperty(name = "inherit-error-handler", type = "boolean"),
+ @YamlProperty(name = "to-type", type = "string")
}
)
public static class TransformDefinitionDeserializer extends YamlDeserializerBase<TransformDefinition> {
@@ -17102,11 +17187,21 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
target.setExpression(val);
break;
}
+ case "from-type": {
+ String val = asText(node);
+ target.setFromType(val);
+ break;
+ }
case "inherit-error-handler": {
String val = asText(node);
target.setInheritErrorHandler(java.lang.Boolean.valueOf(val));
break;
}
+ case "to-type": {
+ String val = asText(node);
+ target.setToType(val);
+ break;
+ }
case "id": {
String val = asText(node);
target.setId(val);
@@ -17141,7 +17236,8 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
properties = {
@YamlProperty(name = "custom-transformer", type = "object:org.apache.camel.model.transformer.CustomTransformerDefinition"),
@YamlProperty(name = "data-format-transformer", type = "object:org.apache.camel.model.transformer.DataFormatTransformerDefinition"),
- @YamlProperty(name = "endpoint-transformer", type = "object:org.apache.camel.model.transformer.EndpointTransformerDefinition")
+ @YamlProperty(name = "endpoint-transformer", type = "object:org.apache.camel.model.transformer.EndpointTransformerDefinition"),
+ @YamlProperty(name = "load-transformer", type = "object:org.apache.camel.model.transformer.LoadTransformerDefinition")
}
)
public static class TransformersDefinitionDeserializer extends YamlDeserializerBase<TransformersDefinition> {
@@ -17183,6 +17279,16 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
target.setTransformers(existing);
break;
}
+ case "load-transformer": {
+ org.apache.camel.model.transformer.LoadTransformerDefinition val = asType(node, org.apache.camel.model.transformer.LoadTransformerDefinition.class);
+ java.util.List<org.apache.camel.model.transformer.TransformerDefinition> existing = target.getTransformers();
+ if (existing == null) {
+ existing = new java.util.ArrayList<>();
+ }
+ existing.add(val);
+ target.setTransformers(existing);
+ break;
+ }
case "custom-transformer": {
org.apache.camel.model.transformer.CustomTransformerDefinition val = asType(node, org.apache.camel.model.transformer.CustomTransformerDefinition.class);
java.util.List<org.apache.camel.model.transformer.TransformerDefinition> existing = target.getTransformers();
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java
index 3f512865fa4..960fdb05881 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl-deserializers/src/generated/java/org/apache/camel/dsl/yaml/deserializers/ModelDeserializersResolver.java
@@ -226,6 +226,7 @@ public final class ModelDeserializersResolver implements YamlDeserializerResolve
case "load-balance": return new ModelDeserializers.LoadBalanceDefinitionDeserializer();
case "loadBalance": return new ModelDeserializers.LoadBalanceDefinitionDeserializer();
case "org.apache.camel.model.LoadBalanceDefinition": return new ModelDeserializers.LoadBalanceDefinitionDeserializer();
+ case "org.apache.camel.model.transformer.LoadTransformerDefinition": return new ModelDeserializers.LoadTransformerDefinitionDeserializer();
case "log": return new ModelDeserializers.LogDefinitionDeserializer();
case "org.apache.camel.model.LogDefinition": return new ModelDeserializers.LogDefinitionDeserializer();
case "loop": return new ModelDeserializers.LoopDefinitionDeserializer();
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camel-yaml-dsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camel-yaml-dsl.json
index 76e1cb9eef9..5d7127bcd0e 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camel-yaml-dsl.json
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camel-yaml-dsl.json
@@ -2491,6 +2491,9 @@
"id" : {
"type" : "string"
},
+ "input-type" : {
+ "$ref" : "#/items/definitions/org.apache.camel.model.InputTypeDefinition"
+ },
"log-mask" : {
"type" : "boolean"
},
@@ -2500,6 +2503,9 @@
"node-prefix-id" : {
"type" : "string"
},
+ "output-type" : {
+ "$ref" : "#/items/definitions/org.apache.camel.model.OutputTypeDefinition"
+ },
"precondition" : {
"type" : "string"
},
@@ -3332,11 +3338,17 @@
"expression" : {
"$ref" : "#/items/definitions/org.apache.camel.model.language.ExpressionDefinition"
},
+ "from-type" : {
+ "type" : "string"
+ },
"id" : {
"type" : "string"
},
"inherit-error-handler" : {
"type" : "boolean"
+ },
+ "to-type" : {
+ "type" : "string"
}
}
},
@@ -8008,6 +8020,9 @@
"from-type" : {
"type" : "string"
},
+ "name" : {
+ "type" : "string"
+ },
"ref" : {
"type" : "string"
},
@@ -8091,6 +8106,9 @@
"mime-multipart" : {
"$ref" : "#/items/definitions/org.apache.camel.model.dataformat.MimeMultipartDataFormat"
},
+ "name" : {
+ "type" : "string"
+ },
"parquet-avro" : {
"$ref" : "#/items/definitions/org.apache.camel.model.dataformat.ParquetAvroDataFormat"
},
@@ -8159,6 +8177,9 @@
"from-type" : {
"type" : "string"
},
+ "name" : {
+ "type" : "string"
+ },
"ref" : {
"type" : "string"
},
@@ -8173,6 +8194,29 @@
}
}
},
+ "org.apache.camel.model.transformer.LoadTransformerDefinition" : {
+ "type" : "object",
+ "properties" : {
+ "defaults" : {
+ "type" : "boolean"
+ },
+ "from-type" : {
+ "type" : "string"
+ },
+ "name" : {
+ "type" : "string"
+ },
+ "package-scan" : {
+ "type" : "string"
+ },
+ "scheme" : {
+ "type" : "string"
+ },
+ "to-type" : {
+ "type" : "string"
+ }
+ }
+ },
"org.apache.camel.model.transformer.TransformersDefinition" : {
"type" : "object",
"properties" : {
@@ -8184,6 +8228,9 @@
},
"endpoint-transformer" : {
"$ref" : "#/items/definitions/org.apache.camel.model.transformer.EndpointTransformerDefinition"
+ },
+ "load-transformer" : {
+ "$ref" : "#/items/definitions/org.apache.camel.model.transformer.LoadTransformerDefinition"
}
}
},
diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
index 06c320f6d52..ed5bc50550e 100644
--- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
+++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/schema/camelYamlDsl.json
@@ -2401,6 +2401,9 @@
"id" : {
"type" : "string"
},
+ "inputType" : {
+ "$ref" : "#/items/definitions/org.apache.camel.model.InputTypeDefinition"
+ },
"logMask" : {
"type" : "boolean"
},
@@ -2410,6 +2413,9 @@
"nodePrefixId" : {
"type" : "string"
},
+ "outputType" : {
+ "$ref" : "#/items/definitions/org.apache.camel.model.OutputTypeDefinition"
+ },
"precondition" : {
"type" : "string"
},
@@ -3242,11 +3248,17 @@
"expression" : {
"$ref" : "#/items/definitions/org.apache.camel.model.language.ExpressionDefinition"
},
+ "fromType" : {
+ "type" : "string"
+ },
"id" : {
"type" : "string"
},
"inheritErrorHandler" : {
"type" : "boolean"
+ },
+ "toType" : {
+ "type" : "string"
}
}
},
@@ -7915,6 +7927,9 @@
"fromType" : {
"type" : "string"
},
+ "name" : {
+ "type" : "string"
+ },
"ref" : {
"type" : "string"
},
@@ -7998,6 +8013,9 @@
"mimeMultipart" : {
"$ref" : "#/items/definitions/org.apache.camel.model.dataformat.MimeMultipartDataFormat"
},
+ "name" : {
+ "type" : "string"
+ },
"parquetAvro" : {
"$ref" : "#/items/definitions/org.apache.camel.model.dataformat.ParquetAvroDataFormat"
},
@@ -8066,6 +8084,9 @@
"fromType" : {
"type" : "string"
},
+ "name" : {
+ "type" : "string"
+ },
"ref" : {
"type" : "string"
},
@@ -8080,6 +8101,29 @@
}
}
},
+ "org.apache.camel.model.transformer.LoadTransformerDefinition" : {
+ "type" : "object",
+ "properties" : {
+ "defaults" : {
+ "type" : "boolean"
+ },
+ "fromType" : {
+ "type" : "string"
+ },
+ "name" : {
+ "type" : "string"
+ },
+ "packageScan" : {
+ "type" : "string"
+ },
+ "scheme" : {
+ "type" : "string"
+ },
+ "toType" : {
+ "type" : "string"
+ }
+ }
+ },
"org.apache.camel.model.transformer.TransformersDefinition" : {
"type" : "object",
"properties" : {
@@ -8091,6 +8135,9 @@
},
"endpointTransformer" : {
"$ref" : "#/items/definitions/org.apache.camel.model.transformer.EndpointTransformerDefinition"
+ },
+ "loadTransformer" : {
+ "$ref" : "#/items/definitions/org.apache.camel.model.transformer.LoadTransformerDefinition"
}
}
},