This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push: new 10d0f5c6e37 Allow Smooks execution context to be overridden via header (#16129) 10d0f5c6e37 is described below commit 10d0f5c6e37621805d9e305f09b93526a96b5e98 Author: cjmamo <823038+cjm...@users.noreply.github.com> AuthorDate: Thu Oct 31 10:17:15 2024 +0100 Allow Smooks execution context to be overridden via header (#16129) * feat: allow Smooks execution context to be overridden via header doc: document SmooksExecutionContext header remove tabs from smooks-dataformat.adoc * docs: change to advanced * chore: regenerate --- .../apache/camel/catalog/components/smooks.json | 3 ++ .../org/apache/camel/component/smooks/smooks.json | 3 ++ .../src/main/docs/smooks-component.adoc | 4 ++ .../src/main/docs/smooks-dataformat.adoc | 6 +-- .../camel/component/smooks/SmooksConstants.java | 29 ++++++++++++++ .../camel/component/smooks/SmooksEndpoint.java | 2 +- .../camel/component/smooks/SmooksProcessor.java | 29 +++++++------- .../component/smooks/SmooksProcessorTest.java | 45 ++++++++++++++++++++++ .../endpoint/dsl/SmooksEndpointBuilderFactory.java | 37 ++++++++++++++++++ 9 files changed, 140 insertions(+), 18 deletions(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smooks.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smooks.json index 3eeb420617c..4525d223b10 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smooks.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smooks.json @@ -28,6 +28,9 @@ "autowiredEnabled": { "index": 1, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching t [...] "smooksFactory": { "index": 2, "kind": "property", "displayName": "Smooks Factory", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.smooks.SmooksFactory", "deprecated": false, "autowired": true, "secret": false, "description": "To use a custom factory for creating Smooks." } }, + "headers": { + "CamelSmooksExecutionContext": { "index": 0, "kind": "header", "displayName": "", "group": "advanced", "label": "advanced", "required": false, "javaType": "org.smooks.api.ExecutionContext", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The Smooks execution context.", "constantName": "org.apache.camel.component.smooks.SmooksConstants#SMOOKS_EXECUTION_CONTEXT" } + }, "properties": { "smooksConfig": { "index": 0, "kind": "path", "displayName": "Smooks Config", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "supportFileReference": true, "description": "Path to the Smooks configuration file" }, "reportPath": { "index": 1, "kind": "parameter", "displayName": "Report Path", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "File path to place the generated HTML execution report. The report is a useful tool in the developers arsenal for diagnosing issues or comprehending a transformation. Do not set in production since this is a major performance drain" }, diff --git a/components/camel-smooks/src/generated/resources/META-INF/org/apache/camel/component/smooks/smooks.json b/components/camel-smooks/src/generated/resources/META-INF/org/apache/camel/component/smooks/smooks.json index 3eeb420617c..4525d223b10 100644 --- a/components/camel-smooks/src/generated/resources/META-INF/org/apache/camel/component/smooks/smooks.json +++ b/components/camel-smooks/src/generated/resources/META-INF/org/apache/camel/component/smooks/smooks.json @@ -28,6 +28,9 @@ "autowiredEnabled": { "index": 1, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching t [...] "smooksFactory": { "index": 2, "kind": "property", "displayName": "Smooks Factory", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.smooks.SmooksFactory", "deprecated": false, "autowired": true, "secret": false, "description": "To use a custom factory for creating Smooks." } }, + "headers": { + "CamelSmooksExecutionContext": { "index": 0, "kind": "header", "displayName": "", "group": "advanced", "label": "advanced", "required": false, "javaType": "org.smooks.api.ExecutionContext", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The Smooks execution context.", "constantName": "org.apache.camel.component.smooks.SmooksConstants#SMOOKS_EXECUTION_CONTEXT" } + }, "properties": { "smooksConfig": { "index": 0, "kind": "path", "displayName": "Smooks Config", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "supportFileReference": true, "description": "Path to the Smooks configuration file" }, "reportPath": { "index": 1, "kind": "parameter", "displayName": "Report Path", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "File path to place the generated HTML execution report. The report is a useful tool in the developers arsenal for diagnosing issues or comprehending a transformation. Do not set in production since this is a major performance drain" }, diff --git a/components/camel-smooks/src/main/docs/smooks-component.adoc b/components/camel-smooks/src/main/docs/smooks-component.adoc index 93f917a6e85..722216baf5b 100644 --- a/components/camel-smooks/src/main/docs/smooks-component.adoc +++ b/components/camel-smooks/src/main/docs/smooks-component.adoc @@ -56,6 +56,10 @@ include::partial$component-endpoint-options.adoc[] // endpoint options: END +// component headers: START +include::partial$component-endpoint-headers.adoc[] +// component headers: END + == Usage Using the Smooks component lets you leverage all the features of Smooks, such as transformation and fragment-driven routing, from within Camel. You can take an existing Smooks configuration and use this in your Camel routes as shown below: diff --git a/components/camel-smooks/src/main/docs/smooks-dataformat.adoc b/components/camel-smooks/src/main/docs/smooks-dataformat.adoc index 667bee73142..6b83b71002a 100644 --- a/components/camel-smooks/src/main/docs/smooks-dataformat.adoc +++ b/components/camel-smooks/src/main/docs/smooks-dataformat.adoc @@ -66,9 +66,9 @@ The Smooks configuration in `csv-smooks-unmarshal-config.xml` is as follows: <core:result type="org.smooks.io.sink.JavaSink" extract="result"/> </core:exports> - <csv:reader fields="firstName,lastName,gender,age,country"> - <csv:listBinding beanId="result" class="org.smooks.example.Customer"/> - </csv:reader> + <csv:reader fields="firstName,lastName,gender,age,country"> + <csv:listBinding beanId="result" class="org.smooks.example.Customer"/> + </csv:reader> </smooks-resource-list> ---- diff --git a/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/SmooksConstants.java b/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/SmooksConstants.java new file mode 100644 index 00000000000..1c7e6622dea --- /dev/null +++ b/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/SmooksConstants.java @@ -0,0 +1,29 @@ +/* + * 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.smooks; + +import org.apache.camel.spi.Metadata; + +/** + * Smooks constants + */ +public final class SmooksConstants { + + @Metadata(label = "advanced", description = "The Smooks execution context.", + javaType = "org.smooks.api.ExecutionContext") + public static final String SMOOKS_EXECUTION_CONTEXT = "CamelSmooksExecutionContext"; +} diff --git a/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/SmooksEndpoint.java b/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/SmooksEndpoint.java index f001a506774..1091f79d9cb 100644 --- a/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/SmooksEndpoint.java +++ b/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/SmooksEndpoint.java @@ -33,7 +33,7 @@ import org.apache.camel.support.service.ServiceHelper; */ @UriEndpoint(firstVersion = "4.7.0", scheme = "smooks", title = "Smooks", syntax = "smooks:smooksConfig", producerOnly = true, - category = { Category.TRANSFORMATION }) + category = { Category.TRANSFORMATION }, headersClass = SmooksConstants.class) public class SmooksEndpoint extends DefaultEndpoint { @UriPath(description = "Path to the Smooks configuration file") diff --git a/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/SmooksProcessor.java b/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/SmooksProcessor.java index 1a318ac6f17..5f1ab2492c6 100644 --- a/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/SmooksProcessor.java +++ b/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/SmooksProcessor.java @@ -73,8 +73,6 @@ import org.smooks.io.source.URLSource; */ public class SmooksProcessor extends ServiceSupport implements Processor, CamelContextAware { - public static final String SMOOKS_EXECUTION_CONTEXT = "CamelSmooksExecutionContext"; - private static final TypedKey<Exchange> EXCHANGE_TYPED_KEY = TypedKey.of(); private static final Logger LOG = LoggerFactory.getLogger(SmooksProcessor.class); @@ -110,16 +108,20 @@ public class SmooksProcessor extends ServiceSupport implements Processor, CamelC } public void process(final Exchange exchange) { - final ExecutionContext executionContext = smooks.createExecutionContext(); - try { - executionContext.put(EXCHANGE_TYPED_KEY, exchange); + ExecutionContext executionContext + = exchange.getIn().getHeader(SmooksConstants.SMOOKS_EXECUTION_CONTEXT, ExecutionContext.class); + if (executionContext == null) { + executionContext = smooks.createExecutionContext(); Charset charset = ExchangeHelper.getCharset(exchange, false); if (charset != null) { - // if provided use the came character encoding + // if provided use the same character encoding executionContext.setContentEncoding(charset.name()); } - exchange.getIn().setHeader(SMOOKS_EXECUTION_CONTEXT, executionContext); - setupSmooksReporting(executionContext); + } + try { + executionContext.put(EXCHANGE_TYPED_KEY, exchange); + exchange.getIn().setHeader(SmooksConstants.SMOOKS_EXECUTION_CONTEXT, executionContext); + setUpSmooksReporting(executionContext); final Exports exports = smooks.getApplicationContext().getRegistry().lookup(new ExportsLookup()); if (exports.hasExports()) { @@ -150,15 +152,14 @@ public class SmooksProcessor extends ServiceSupport implements Processor, CamelC } } - private void setupSmooksReporting(final ExecutionContext executionContext) { + private void setUpSmooksReporting(final ExecutionContext executionContext) { if (reportPath != null) { try { executionContext.getContentDeliveryRuntime().addExecutionEventListener( new HtmlReportGenerator(reportPath, executionContext.getApplicationContext())); } catch (final IOException e) { - LOG.warn("Cannot generate Smooks Report. The reportPath specified was [" + reportPath - + "]. This exception is ignored.", - e); + LOG.warn("Cannot generate Smooks Report. The reportPath specified was [{}]. This exception is ignored.", + reportPath, e); } } } @@ -258,7 +259,7 @@ public class SmooksProcessor extends ServiceSupport implements Processor, CamelC } @Override - protected void doStart() throws Exception { + protected void doStart() { try { if (smooks == null) { smooks = createSmooks(); @@ -278,7 +279,7 @@ public class SmooksProcessor extends ServiceSupport implements Processor, CamelC } @Override - protected void doStop() throws Exception { + protected void doStop() { if (smooks != null) { IOHelper.close(smooks); smooks = null; diff --git a/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/SmooksProcessorTest.java b/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/SmooksProcessorTest.java index 0be3e26f2cd..9ac2752fc71 100644 --- a/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/SmooksProcessorTest.java +++ b/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/SmooksProcessorTest.java @@ -38,6 +38,8 @@ import org.apache.camel.support.DefaultExchange; import org.apache.camel.test.junit5.CamelTestSupport; import org.junit.jupiter.api.Test; import org.smooks.Smooks; +import org.smooks.SmooksFactory; +import org.smooks.api.ExecutionContext; import org.smooks.cartridges.javabean.Bean; import org.smooks.cartridges.javabean.Value; import org.smooks.io.payload.Exports; @@ -58,6 +60,7 @@ import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; public class SmooksProcessorTest extends CamelTestSupport { @@ -78,6 +81,7 @@ public class SmooksProcessorTest extends CamelTestSupport { assertIsSatisfied(); Exchange exchange = result.assertExchangeReceived(0); + assertNotNull(exchange.getMessage().getHeader(SmooksConstants.SMOOKS_EXECUTION_CONTEXT, ExecutionContext.class)); assertIsInstanceOf(InputStreamCache.class, exchange.getIn().getBody()); assertFalse(DiffBuilder.compare(getExpectedOrderXml()).withTest(exchange.getIn().getBody(String.class)).ignoreComments() .ignoreWhitespace().build().hasDifferences()); @@ -90,6 +94,47 @@ public class SmooksProcessorTest extends CamelTestSupport { assertOneProcessedMessage(); } + @Test + public void testProcessUsesExistingExecutionContextWhenExecutionContextIsInHeader() throws Exception { + Smooks smooks = new Smooks(); + SmooksProcessor processor = new SmooksProcessor("edi-to-xml-smooks-config.xml", context); + processor.setSmooksFactory(new SmooksFactory() { + @Override + public Smooks createInstance() { + return smooks; + } + + @Override + public Smooks createInstance(InputStream config) { + return null; + } + + @Override + public Smooks createInstance(String config) { + return null; + } + }); + + final ExecutionContext[] executionContext = new ExecutionContext[1]; + context.addRoutes(new RouteBuilder() { + @Override + public void configure() { + from("direct:input") + .setHeader(SmooksConstants.SMOOKS_EXECUTION_CONTEXT, () -> { + executionContext[0] = smooks.createExecutionContext(); + return executionContext[0]; + }) + .process(processor).to("mock:result"); + } + + }); + context.start(); + template.sendBody("direct://input", getOrderEdi()); + + Exchange exchange = result.assertExchangeReceived(0); + assertEquals(executionContext[0], exchange.getMessage().getHeader(SmooksConstants.SMOOKS_EXECUTION_CONTEXT)); + } + @Test public void testProcessGivenAttachment() throws Exception { context.addRoutes(createEdiToXmlRouteBuilder()); diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SmooksEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SmooksEndpointBuilderFactory.java index 3d31dcefdcd..e5be1f84cf4 100644 --- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SmooksEndpointBuilderFactory.java +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/SmooksEndpointBuilderFactory.java @@ -123,6 +123,20 @@ public interface SmooksEndpointBuilderFactory { } public interface SmooksBuilders { + /** + * Smooks (camel-smooks) + * Use Smooks to transform, route, and bind both XML and non-XML data, + * including EDI, CSV, JSON, and YAML. + * + * Category: transformation + * Since: 4.7 + * Maven coordinates: org.apache.camel:camel-smooks + * + * @return the dsl builder for the headers' name. + */ + default SmooksHeaderNameBuilder smooks() { + return SmooksHeaderNameBuilder.INSTANCE; + } /** * Smooks (camel-smooks) * Use Smooks to transform, route, and bind both XML and non-XML data, @@ -171,6 +185,29 @@ public interface SmooksEndpointBuilderFactory { } } + /** + * The builder of headers' name for the Smooks component. + */ + public static class SmooksHeaderNameBuilder { + /** + * The internal instance of the builder used to access to all the + * methods representing the name of headers. + */ + private static final SmooksHeaderNameBuilder INSTANCE = new SmooksHeaderNameBuilder(); + + /** + * The Smooks execution context. + * + * The option is a: {@code org.smooks.api.ExecutionContext} type. + * + * Group: advanced + * + * @return the name of the header {@code SmooksExecutionContext}. + */ + public String smooksExecutionContext() { + return "CamelSmooksExecutionContext"; + } + } static SmooksEndpointBuilder endpointBuilder(String componentName, String path) { class SmooksEndpointBuilderImpl extends AbstractEndpointBuilder implements SmooksEndpointBuilder, AdvancedSmooksEndpointBuilder { public SmooksEndpointBuilderImpl(String path) {