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 295c7871cf3 fix: solve issue where having more than one Smooks endpoint on the same route implicitly referencing via header the same execution context could cause Smooks to misbehave (#16141) 295c7871cf3 is described below commit 295c7871cf351340021795d6d38258e0c3e92ca9 Author: cjmamo <823038+cjm...@users.noreply.github.com> AuthorDate: Sat Nov 2 08:11:39 2024 +0100 fix: solve issue where having more than one Smooks endpoint on the same route implicitly referencing via header the same execution context could cause Smooks to misbehave (#16141) Refs: https://github.com/apache/camel/pull/16129 --- .../apache/camel/catalog/components/smooks.json | 3 +- .../component/smooks/SmooksEndpointConfigurer.java | 6 +++ .../component/smooks/SmooksEndpointUriFactory.java | 3 +- .../org/apache/camel/component/smooks/smooks.json | 3 +- .../camel/component/smooks/SmooksEndpoint.java | 17 ++++++- .../camel/component/smooks/SmooksProcessor.java | 17 ++++++- .../component/smooks/SmooksProcessorTest.java | 52 +++++++++++++++++++++- .../endpoint/dsl/SmooksEndpointBuilderFactory.java | 33 ++++++++++++++ 8 files changed, 125 insertions(+), 9 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 4525d223b10..7416ef4bfb4 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 @@ -34,6 +34,7 @@ "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" }, - "lazyStartProducer": { "index": 2, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produc [...] + "lazyStartProducer": { "index": 2, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produc [...] + "allowExecutionContextFromHeader": { "index": 3, "kind": "parameter", "displayName": "Allow Execution Context From Header", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "false", "description": "Allow execution context to be set from the CamelSmooksExecutionContext header" } } } diff --git a/components/camel-smooks/src/generated/java/org/apache/camel/component/smooks/SmooksEndpointConfigurer.java b/components/camel-smooks/src/generated/java/org/apache/camel/component/smooks/SmooksEndpointConfigurer.java index 74e8088e31d..5358bdf4c61 100644 --- a/components/camel-smooks/src/generated/java/org/apache/camel/component/smooks/SmooksEndpointConfigurer.java +++ b/components/camel-smooks/src/generated/java/org/apache/camel/component/smooks/SmooksEndpointConfigurer.java @@ -23,6 +23,8 @@ public class SmooksEndpointConfigurer extends PropertyConfigurerSupport implemen public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) { SmooksEndpoint target = (SmooksEndpoint) obj; switch (ignoreCase ? name.toLowerCase() : name) { + case "allowexecutioncontextfromheader": + case "allowExecutionContextFromHeader": target.setAllowExecutionContextFromHeader(property(camelContext, java.lang.Boolean.class, value)); return true; case "lazystartproducer": case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; case "reportpath": @@ -34,6 +36,8 @@ public class SmooksEndpointConfigurer extends PropertyConfigurerSupport implemen @Override public Class<?> getOptionType(String name, boolean ignoreCase) { switch (ignoreCase ? name.toLowerCase() : name) { + case "allowexecutioncontextfromheader": + case "allowExecutionContextFromHeader": return java.lang.Boolean.class; case "lazystartproducer": case "lazyStartProducer": return boolean.class; case "reportpath": @@ -46,6 +50,8 @@ public class SmooksEndpointConfigurer extends PropertyConfigurerSupport implemen public Object getOptionValue(Object obj, String name, boolean ignoreCase) { SmooksEndpoint target = (SmooksEndpoint) obj; switch (ignoreCase ? name.toLowerCase() : name) { + case "allowexecutioncontextfromheader": + case "allowExecutionContextFromHeader": return target.getAllowExecutionContextFromHeader(); case "lazystartproducer": case "lazyStartProducer": return target.isLazyStartProducer(); case "reportpath": diff --git a/components/camel-smooks/src/generated/java/org/apache/camel/component/smooks/SmooksEndpointUriFactory.java b/components/camel-smooks/src/generated/java/org/apache/camel/component/smooks/SmooksEndpointUriFactory.java index f1d0e702ae0..b1412b5e968 100644 --- a/components/camel-smooks/src/generated/java/org/apache/camel/component/smooks/SmooksEndpointUriFactory.java +++ b/components/camel-smooks/src/generated/java/org/apache/camel/component/smooks/SmooksEndpointUriFactory.java @@ -23,7 +23,8 @@ public class SmooksEndpointUriFactory extends org.apache.camel.support.component private static final Set<String> SECRET_PROPERTY_NAMES; private static final Set<String> MULTI_VALUE_PREFIXES; static { - Set<String> props = new HashSet<>(3); + Set<String> props = new HashSet<>(4); + props.add("allowExecutionContextFromHeader"); props.add("lazyStartProducer"); props.add("reportPath"); props.add("smooksConfig"); 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 4525d223b10..7416ef4bfb4 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 @@ -34,6 +34,7 @@ "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" }, - "lazyStartProducer": { "index": 2, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produc [...] + "lazyStartProducer": { "index": 2, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produc [...] + "allowExecutionContextFromHeader": { "index": 3, "kind": "parameter", "displayName": "Allow Execution Context From Header", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "false", "description": "Allow execution context to be set from the CamelSmooksExecutionContext header" } } } 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 1091f79d9cb..22ee794fba8 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 @@ -41,6 +41,11 @@ public class SmooksEndpoint extends DefaultEndpoint { private String smooksConfig; @UriParam(description = "File path to place the generated HTML execution report. The report is a useful tool in the developer’s arsenal for diagnosing issues or comprehending a transformation. Do not set in production since this is a major performance drain") private String reportPath; + @UriParam(description = "Allow execution context to be set from the " + SmooksConstants.SMOOKS_EXECUTION_CONTEXT + + " header", + label = "advanced", + defaultValue = "false") + private Boolean allowExecutionContextFromHeader = false; private final SmooksProcessor smooksProcessor; @@ -50,12 +55,12 @@ public class SmooksEndpoint extends DefaultEndpoint { } @Override - public Producer createProducer() throws Exception { + public Producer createProducer() { return new SmooksProducer(this, smooksProcessor); } @Override - public Consumer createConsumer(Processor processor) throws Exception { + public Consumer createConsumer(Processor processor) { throw new IllegalArgumentException("Consumer is not supported"); } @@ -86,4 +91,12 @@ public class SmooksEndpoint extends DefaultEndpoint { public void setReportPath(String reportPath) { this.reportPath = reportPath; } + + public Boolean getAllowExecutionContextFromHeader() { + return allowExecutionContextFromHeader; + } + + public void setAllowExecutionContextFromHeader(Boolean allowExecutionContextFromHeader) { + this.allowExecutionContextFromHeader = allowExecutionContextFromHeader; + } } 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 5f1ab2492c6..605ac7f78aa 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 @@ -80,6 +80,7 @@ public class SmooksProcessor extends ServiceSupport implements Processor, CamelC private Smooks smooks; private String configUri; private String reportPath; + private Boolean allowExecutionContextFromHeader = false; private final Set<VisitorAppender> visitorAppender = new HashSet<>(); private final Map<String, Visitor> selectorVisitorMap = new HashMap<>(); @@ -107,9 +108,20 @@ public class SmooksProcessor extends ServiceSupport implements Processor, CamelC return camelContext; } + public Boolean getAllowExecutionContextFromHeader() { + return allowExecutionContextFromHeader; + } + + public void setAllowExecutionContextFromHeader(Boolean allowExecutionContextFromHeader) { + this.allowExecutionContextFromHeader = allowExecutionContextFromHeader; + } + public void process(final Exchange exchange) { - ExecutionContext executionContext - = exchange.getIn().getHeader(SmooksConstants.SMOOKS_EXECUTION_CONTEXT, ExecutionContext.class); + ExecutionContext executionContext = null; + if (allowExecutionContextFromHeader) { + executionContext + = exchange.getMessage().getHeader(SmooksConstants.SMOOKS_EXECUTION_CONTEXT, ExecutionContext.class); + } if (executionContext == null) { executionContext = smooks.createExecutionContext(); Charset charset = ExchangeHelper.getCharset(exchange, false); @@ -118,6 +130,7 @@ public class SmooksProcessor extends ServiceSupport implements Processor, CamelC executionContext.setContentEncoding(charset.name()); } } + try { executionContext.put(EXCHANGE_TYPED_KEY, exchange); exchange.getIn().setHeader(SmooksConstants.SMOOKS_EXECUTION_CONTEXT, executionContext); 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 9ac2752fc71..79cd2633780 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 @@ -60,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.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -95,7 +96,8 @@ public class SmooksProcessorTest extends CamelTestSupport { } @Test - public void testProcessUsesExistingExecutionContextWhenExecutionContextIsInHeader() throws Exception { + public void testProcessUsesExistingExecutionContextWhenExecutionContextIsInHeaderAndAllowExecutionContextFromHeaderIsTrue() + throws Exception { Smooks smooks = new Smooks(); SmooksProcessor processor = new SmooksProcessor("edi-to-xml-smooks-config.xml", context); processor.setSmooksFactory(new SmooksFactory() { @@ -114,6 +116,7 @@ public class SmooksProcessorTest extends CamelTestSupport { return null; } }); + processor.setAllowExecutionContextFromHeader(true); final ExecutionContext[] executionContext = new ExecutionContext[1]; context.addRoutes(new RouteBuilder() { @@ -124,7 +127,8 @@ public class SmooksProcessorTest extends CamelTestSupport { executionContext[0] = smooks.createExecutionContext(); return executionContext[0]; }) - .process(processor).to("mock:result"); + .process(processor) + .to("mock:result"); } }); @@ -135,6 +139,50 @@ public class SmooksProcessorTest extends CamelTestSupport { assertEquals(executionContext[0], exchange.getMessage().getHeader(SmooksConstants.SMOOKS_EXECUTION_CONTEXT)); } + @Test + public void testProcessDoesNotUseExistingExecutionContextWhenExecutionContextIsInHeaderAndAllowExecutionContextFromHeaderIsFalse() + 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; + } + }); + processor.setAllowExecutionContextFromHeader(false); + + 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); + assertNotEquals(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 e5be1f84cf4..58b2d7b959b 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 @@ -120,6 +120,39 @@ public interface SmooksEndpointBuilderFactory { doSetProperty("lazyStartProducer", lazyStartProducer); return this; } + /** + * Allow execution context to be set from the + * CamelSmooksExecutionContext header. + * + * The option is a: <code>java.lang.Boolean</code> type. + * + * Default: false + * Group: advanced + * + * @param allowExecutionContextFromHeader the value to set + * @return the dsl builder + */ + default AdvancedSmooksEndpointBuilder allowExecutionContextFromHeader(Boolean allowExecutionContextFromHeader) { + doSetProperty("allowExecutionContextFromHeader", allowExecutionContextFromHeader); + return this; + } + /** + * Allow execution context to be set from the + * CamelSmooksExecutionContext header. + * + * The option will be converted to a <code>java.lang.Boolean</code> + * type. + * + * Default: false + * Group: advanced + * + * @param allowExecutionContextFromHeader the value to set + * @return the dsl builder + */ + default AdvancedSmooksEndpointBuilder allowExecutionContextFromHeader(String allowExecutionContextFromHeader) { + doSetProperty("allowExecutionContextFromHeader", allowExecutionContextFromHeader); + return this; + } } public interface SmooksBuilders {