You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2024/12/16 09:48:05 UTC

(camel) branch main updated: CAMEL-21547: Migrate bean routing functionality from Smooks Cartridge to Smooks Component (#16563)

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 3c0dbfafab8 CAMEL-21547: Migrate bean routing functionality from Smooks Cartridge to Smooks Component (#16563)
3c0dbfafab8 is described below

commit 3c0dbfafab8c61a753dc013ca0a49a9ecf3e7217
Author: cjmamo <82...@users.noreply.github.com>
AuthorDate: Mon Dec 16 10:47:59 2024 +0100

    CAMEL-21547: Migrate bean routing functionality from Smooks Cartridge to Smooks Component (#16563)
    
    * CAMEL-21547: migrate bean routing functionality from Smooks Cartridge to Smooks Component
    
    * docs: remove author comments
---
 components/camel-smooks/pom.xml                    |   9 +-
 .../src/main/docs/smooks-component.adoc            |  55 ++++-
 .../camel/component/smooks/routing/BeanRouter.java | 238 +++++++++++++++++++++
 .../smooks/routing/BeanRouterObserver.java         |  87 ++++++++
 .../resources/META-INF/xsd/smooks/camel-1.5.xsd    | 104 +++++++++
 .../META-INF/xsd/smooks/camel-1.5.xsd-smooks.xml   |  80 +++++++
 .../smooks/routing/BeanRouterFunctionalTest.java   |  48 +++++
 .../smooks/routing/BeanRouterObserverTest.java     |  69 ++++++
 .../component/smooks/routing/BeanRouterTest.java   | 173 +++++++++++++++
 .../component/smooks/routing/gender/Gender.java    |  22 ++
 .../routing/gender/GenderTypeConverterFactory.java |  34 +++
 .../dataformat/smooks/SmooksDataFormatTest.java    |   2 +-
 .../org.smooks.api.converter.TypeConverterFactory  |   1 +
 .../test/resources/bean-routing-smooks-config.xml  |  38 ++++
 .../src/test/resources/xml/customer.xml            |   2 +-
 .../src/test/resources/xml/expected-customer.xml   |   2 +-
 16 files changed, 955 insertions(+), 9 deletions(-)

diff --git a/components/camel-smooks/pom.xml b/components/camel-smooks/pom.xml
index 79eabd666e7..ac7ed60f571 100644
--- a/components/camel-smooks/pom.xml
+++ b/components/camel-smooks/pom.xml
@@ -55,15 +55,18 @@
             <groupId>org.smooks</groupId>
             <artifactId>smooks-core</artifactId>
         </dependency>
-
+        <dependency>
+            <groupId>org.smooks.cartridges</groupId>
+            <artifactId>smooks-javabean-cartridge</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.smooks.cartridges.edi</groupId>
             <artifactId>smooks-edi-cartridge</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.smooks.cartridges</groupId>
-            <artifactId>smooks-javabean-cartridge</artifactId>
+            <groupId>org.smooks</groupId>
+            <artifactId>smooks-test-kit</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git a/components/camel-smooks/src/main/docs/smooks-component.adoc b/components/camel-smooks/src/main/docs/smooks-component.adoc
index 722216baf5b..8e6d214f437 100644
--- a/components/camel-smooks/src/main/docs/smooks-component.adoc
+++ b/components/camel-smooks/src/main/docs/smooks-component.adoc
@@ -62,7 +62,7 @@ include::partial$component-endpoint-headers.adoc[]
 
 == 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:
+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 reference it from your Camel routes as shown below:
 
 [tabs]
 ====
@@ -87,7 +87,7 @@ YAML::
 ----
 ====
 
-The Smooks component is configured with a mandatory configuration file, which is `smooks-config.xml` in the example above. It is not clear what type of output the component is producing from looking at the above route. By default, the message body output is a stream but the type of output can be changed by configuring `{https://www.smooks.org/xsd/smooks/smooks-core-1.6.xsd}exports` in `smooks-config.xml` as shown in this Smooks configuration:
+The Smooks component is configured with a mandatory configuration file, which is `smooks-config.xml` in the example above. It is not clear what type of output the component is producing from looking at the above route. By default, the message body output is a stream but the type of output can be changed by configuring `{https://www.smooks.org/xsd/smooks/smooks-core-1.6.xsd}exports` in the Smooks configuration as shown next:
 
 .smooks-config.xml
 [source,xml]
@@ -106,4 +106,53 @@ The Smooks component is configured with a mandatory configuration file, which is
 </smooks-resource-list>
 ----
 
-The example `<core:exports>` configures Smooks to export the execution result to Camel as a string. Keep in mind that exporting the result as string means that the whole result will be kept in-memory which could cause unexpected performance issues for large payloads.
+The `{https://www.smooks.org/xsd/smooks/smooks-core-1.6.xsd}exports` element in this example configures Smooks to export the execution result to Camel as a string. Keep in mind that exporting the result as string means that the whole result will be kept in-memory which could cause unexpected performance issues for large payloads.
+
+=== Bean routing
+
+Smooks is capable of routing fragments to Camel endpoints using the `{https://www.smooks.org/xsd/smooks/camel-1.5.xsd}route` element from the Smooks configuration. As an example, you can route to an endpoint by declaring the following in your Smooks configuration:
+
+.smooks-config.xml
+[source,xml]
+----
+<smooks-resource-list xmlns="https://www.smooks.org/xsd/smooks-2.0.xsd"
+                      xmlns:jb="https://www.smooks.org/xsd/smooks/javabean-1.6.xsd"
+                      xmlns:camel="https://www.smooks.org/xsd/smooks/camel-1.5.xsd">
+
+  <!-- Create some bean instances from the input source... -->
+  <jb:bean beanId="orderItem"  ...>
+    <!-- etc... See Smooks Java Binding docs -->
+  </jb:bean>
+
+  <!-- Route bean to camel endpoints... -->
+  <camel:route beanId="orderItem">
+    <camel:to endpoint="direct:slow" if="orderItem.priority == 'Normal'"/>
+    <camel:to endpoint="direct:express" if="orderItem.priority == 'High'"/>
+  </camel:route>
+
+</smooks-resource-list>
+----
+
+The above file configures Smooks to route the Java bean `orderItem` in the https://www.smooks.org/documentation/#bean_context[bean context] to the endpoints `direct:slow` and `direct:express`, depending on whether the `priority` field of the `orderItem` instance is equal to `Normal` or `High`. It is possible to route based on an event selector rather than a condition thanks to the `routeOnElement` XML attribute:
+
+.smooks-config.xml
+[source,xml]
+----
+<smooks-resource-list xmlns="https://www.smooks.org/xsd/smooks-2.0.xsd"
+                      xmlns:jb="https://www.smooks.org/xsd/smooks/javabean-1.6.xsd"
+                      xmlns:camel="https://www.smooks.org/xsd/smooks/camel-1.5.xsd">
+
+  <!-- Create some bean instances from the input source... -->
+  <jb:bean beanId="orderItem"  ...>
+    <!-- etc... See Smooks Java Binding docs -->
+  </jb:bean>
+
+  <!-- Route bean to camel endpoints... -->
+  <camel:route beanId="orderItem" routeOnElement="order">
+    <camel:to endpoint="direct:all"/>
+  </camel:route>
+
+</smooks-resource-list>
+----
+
+NOTE: instead of routing complex objects to Camel, a https://www.smooks.org/documentation/#pipeline[pipeline] allows you to have a template (e.g., FreeMarker) reference the beans and then route the evaluated template as string (e.g., XML, CSV, etc...) to Camel.
\ No newline at end of file
diff --git a/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/routing/BeanRouter.java b/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/routing/BeanRouter.java
new file mode 100644
index 00000000000..e07a344ca47
--- /dev/null
+++ b/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/routing/BeanRouter.java
@@ -0,0 +1,238 @@
+/*
+ * 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.routing;
+
+import java.util.Map;
+import java.util.Optional;
+
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.PreDestroy;
+
+import javax.inject.Inject;
+
+import org.w3c.dom.Element;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Message;
+import org.apache.camel.Processor;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.component.smooks.SmooksConstants;
+import org.smooks.api.ApplicationContext;
+import org.smooks.api.ExecutionContext;
+import org.smooks.api.SmooksConfigException;
+import org.smooks.api.SmooksException;
+import org.smooks.api.delivery.ordering.Consumer;
+import org.smooks.api.lifecycle.PostExecutionLifecycle;
+import org.smooks.api.lifecycle.PreExecutionLifecycle;
+import org.smooks.api.resource.config.ResourceConfig;
+import org.smooks.api.resource.visitor.sax.ng.AfterVisitor;
+import org.smooks.assertion.AssertArgument;
+import org.smooks.cartridges.javabean.BeanMapExpressionEvaluator;
+import org.smooks.engine.resource.config.DefaultResourceConfig;
+import org.smooks.support.FreeMarkerTemplate;
+import org.smooks.support.FreeMarkerUtils;
+
+/**
+ * Camel bean routing visitor.
+ *
+ */
+public class BeanRouter implements AfterVisitor, Consumer, PreExecutionLifecycle, PostExecutionLifecycle {
+
+    @Inject
+    protected String beanId;
+
+    @Inject
+    protected String toEndpoint;
+
+    @Inject
+    protected Optional<String> condition;
+
+    @Inject
+    protected Optional<String> correlationIdName;
+
+    @Inject
+    protected Optional<FreeMarkerTemplate> correlationIdPattern;
+
+    @Inject
+    protected ApplicationContext applicationContext;
+
+    @Inject
+    protected ResourceConfig resourceConfig;
+
+    protected ProducerTemplate producerTemplate;
+    protected BeanRouterObserver camelRouterObservable;
+    protected CamelContext camelContext;
+
+    public BeanRouter() {
+    }
+
+    public BeanRouter(final CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
+    @PostConstruct
+    public void postConstruct() {
+        if (resourceConfig == null) {
+            resourceConfig = new DefaultResourceConfig();
+        }
+
+        producerTemplate = getCamelContext().createProducerTemplate();
+        if (isBeanRoutingConfigured()) {
+            camelRouterObservable = new BeanRouterObserver(this, beanId);
+            if (condition != null && condition.isPresent()) {
+                camelRouterObservable.setConditionEvaluator(new BeanMapExpressionEvaluator(condition.get()));
+            }
+        }
+
+        if ((correlationIdName != null && correlationIdName.isPresent())
+                && (correlationIdPattern == null || correlationIdPattern.isEmpty())) {
+            throw new SmooksConfigException(
+                    "Camel router component configured with a 'correlationIdName', but 'correlationIdPattern' is not configured.");
+        }
+        if ((correlationIdName == null || correlationIdName.isEmpty())
+                && (correlationIdPattern != null && correlationIdPattern.isPresent())) {
+            throw new SmooksConfigException(
+                    "Camel router component configured with a 'correlationIdPattern', but 'correlationIdName' is not configured.");
+        }
+    }
+
+    /**
+     * Set the beanId of the bean to be routed.
+     *
+     * @param  beanId the beanId to set
+     * @return        This router instance.
+     */
+    public BeanRouter setBeanId(final String beanId) {
+        this.beanId = beanId;
+        return this;
+    }
+
+    /**
+     * Set the Camel endpoint to which the bean is to be routed.
+     *
+     * @param  toEndpoint the toEndpoint to set
+     * @return            This router instance.
+     */
+    public BeanRouter setToEndpoint(final String toEndpoint) {
+        this.toEndpoint = toEndpoint;
+        return this;
+    }
+
+    /**
+     * Set the correlationId header name.
+     *
+     * @return This router instance.
+     */
+    public BeanRouter setCorrelationIdName(String correlationIdName) {
+        AssertArgument.isNotNullAndNotEmpty(correlationIdName, "correlationIdName");
+        this.correlationIdName = Optional.of(correlationIdName);
+        return this;
+    }
+
+    /**
+     * Set the correlationId pattern used to generate correlationIds.
+     *
+     * @param  correlationIdPattern The pattern generator template.
+     * @return                      This router instance.
+     */
+    public BeanRouter setCorrelationIdPattern(final String correlationIdPattern) {
+        this.correlationIdPattern = Optional.of(new FreeMarkerTemplate(correlationIdPattern));
+        return this;
+    }
+
+    @Override
+    public void visitAfter(final Element element, final ExecutionContext executionContext) throws SmooksException {
+        final Object bean = getBeanFromExecutionContext(executionContext, beanId);
+        sendBean(bean, executionContext);
+    }
+
+    /**
+     * Send the bean to the target endpoint.
+     *
+     * @param bean             The bean to be sent.
+     * @param executionContext The execution context.
+     */
+    protected void sendBean(final Object bean, final ExecutionContext executionContext) {
+        try {
+            if (correlationIdPattern != null && correlationIdPattern.isPresent()) {
+                Processor processor = exchange -> {
+                    Message in = exchange.getIn();
+                    in.setBody(bean);
+                    in.setHeader(correlationIdName.orElse(null),
+                            correlationIdPattern.get().apply(FreeMarkerUtils.getMergedModel(executionContext)));
+                };
+                producerTemplate.send(toEndpoint, processor);
+            } else {
+                producerTemplate.sendBodyAndHeaders(toEndpoint, bean,
+                        Map.of(SmooksConstants.SMOOKS_EXECUTION_CONTEXT, executionContext));
+            }
+        } catch (final Exception e) {
+            throw new SmooksException(String.format("Exception routing beanId [%s] to endpoint [%s]", beanId, toEndpoint), e);
+        }
+    }
+
+    protected Object getBeanFromExecutionContext(final ExecutionContext executionContext, final String beanId) {
+        final Object bean = executionContext.getBeanContext().getBean(beanId);
+        if (bean == null) {
+            throw new SmooksException(
+                    String.format("Exception routing beanId [%s]. The bean was not found in the Smooks execution context",
+                            beanId));
+        }
+
+        return bean;
+    }
+
+    protected CamelContext getCamelContext() {
+        if (camelContext == null) {
+            return applicationContext.getRegistry().lookup(CamelContext.class);
+        } else {
+            return camelContext;
+        }
+    }
+
+    protected boolean isBeanRoutingConfigured() {
+        return "none".equals(resourceConfig.getSelectorPath().getSelector());
+    }
+
+    @PreDestroy
+    public void preDestroy() {
+        try {
+            producerTemplate.stop();
+        } catch (final Exception e) {
+            throw new SmooksException(e.getMessage(), e);
+        }
+    }
+
+    @Override
+    public boolean consumes(final Object object) {
+        return beanId.equals(object);
+    }
+
+    @Override
+    public void onPostExecution(ExecutionContext executionContext) {
+        if (isBeanRoutingConfigured()) {
+            executionContext.getBeanContext().removeObserver(camelRouterObservable);
+        }
+    }
+
+    @Override
+    public void onPreExecution(ExecutionContext executionContext) {
+        if (isBeanRoutingConfigured()) {
+            executionContext.getBeanContext().addObserver(camelRouterObservable);
+        }
+    }
+}
diff --git a/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/routing/BeanRouterObserver.java b/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/routing/BeanRouterObserver.java
new file mode 100644
index 00000000000..8663731ee40
--- /dev/null
+++ b/components/camel-smooks/src/main/java/org/apache/camel/component/smooks/routing/BeanRouterObserver.java
@@ -0,0 +1,87 @@
+/*
+ * 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.routing;
+
+import org.smooks.api.bean.context.BeanContext;
+import org.smooks.api.bean.lifecycle.BeanContextLifecycleEvent;
+import org.smooks.api.bean.lifecycle.BeanContextLifecycleObserver;
+import org.smooks.api.bean.lifecycle.BeanLifecycle;
+import org.smooks.api.expression.ExecutionContextExpressionEvaluator;
+import org.smooks.assertion.AssertArgument;
+
+/**
+ * BeanRouterObserver is a {@link BeanContextLifecycleObserver} that will route a specified bean to the configured
+ * endpoint.
+ * </p>
+ *
+ */
+public class BeanRouterObserver implements BeanContextLifecycleObserver {
+    private final BeanRouter beanRouter;
+    private final String beanId;
+    private ExecutionContextExpressionEvaluator conditionEvaluator;
+
+    /**
+     * Sole contructor.
+     *
+     * @param beanRouter The bean router instance to be used for routing beans.
+     * @param beanId     The beanId which is the beanId in the Smooks {@link BeanContext}.
+     */
+    public BeanRouterObserver(final BeanRouter beanRouter, final String beanId) {
+        AssertArgument.isNotNull(beanRouter, "beanRouter");
+        AssertArgument.isNotNull(beanId, "beanId");
+
+        this.beanRouter = beanRouter;
+        this.beanId = beanId;
+    }
+
+    /**
+     * Set the condition evaluator for performing the routing.
+     * <p/>
+     * Used to test if the routing is to be performed based on the user configured condition.
+     *
+     * @param conditionEvaluator The routing condition evaluator.
+     */
+    public void setConditionEvaluator(ExecutionContextExpressionEvaluator conditionEvaluator) {
+        this.conditionEvaluator = conditionEvaluator;
+    }
+
+    /**
+     * Will route to the endpoint if the BeanLifecycle is of type BeanLifecycle.REMOVE and the beanId is equals to the
+     * beanId that was configured for this instance.
+     */
+    public void onBeanLifecycleEvent(final BeanContextLifecycleEvent event) {
+        if (endEventAndBeanIdMatch(event) && conditionsMatch(event)) {
+            beanRouter.sendBean(event.getBean(), event.getExecutionContext());
+        }
+    }
+
+    private boolean endEventAndBeanIdMatch(final BeanContextLifecycleEvent event) {
+        return event.getLifecycle() == BeanLifecycle.END_FRAGMENT && event.getBeanId().getName().equals(beanId);
+    }
+
+    public boolean conditionsMatch(BeanContextLifecycleEvent event) {
+        if (conditionEvaluator == null) {
+            return true;
+        }
+
+        try {
+            return conditionEvaluator.eval(event.getExecutionContext());
+        } catch (Exception e) {
+            return false;
+        }
+    }
+}
diff --git a/components/camel-smooks/src/main/resources/META-INF/xsd/smooks/camel-1.5.xsd b/components/camel-smooks/src/main/resources/META-INF/xsd/smooks/camel-1.5.xsd
new file mode 100644
index 00000000000..33d32c90b3f
--- /dev/null
+++ b/components/camel-smooks/src/main/resources/META-INF/xsd/smooks/camel-1.5.xsd
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<xs:schema elementFormDefault="qualified"
+	xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="https://www.smooks.org/xsd/smooks/camel-1.5.xsd"
+	xmlns:camel="https://www.smooks.org/xsd/smooks/camel-1.5.xsd"
+	xmlns:smooks="https://www.smooks.org/xsd/smooks-2.0.xsd">
+
+	<xs:import namespace="https://www.smooks.org/xsd/smooks-2.0.xsd" />
+
+	<xs:annotation>
+		<xs:documentation xml:lang="en">Smooks Camel Integration Configuration</xs:documentation>
+	</xs:annotation>
+
+	<xs:element name="route" substitutionGroup="smooks:abstract-resource-config" type="camel:route" />
+	<xs:complexType name="route">
+        <xs:complexContent>
+            <xs:extension base="smooks:abstract-resource-config">
+		        <xs:sequence>
+		            <xs:element name="to" type="camel:to" minOccurs="1" maxOccurs="unbounded" />
+		        </xs:sequence>
+				<xs:attribute name="beanId" type="xs:string" use="required">
+					<xs:annotation>
+						<xs:documentation xml:lang="en">
+							The beanId of the bean to be routed.
+						</xs:documentation>
+					</xs:annotation>
+				</xs:attribute>
+                <xs:attribute name="correlationIdName" type="xs:string">
+                    <xs:annotation>
+                        <xs:documentation xml:lang="en">
+                            Default correlation ID header name e.g. "JMSCorrelationID" when working
+                            with JMS components.
+                            <p/>
+                            This configuration property can be overridden on the "to" child element.
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+                <xs:attribute name="correlationIdPattern" type="xs:string">
+                    <xs:annotation>
+                        <xs:documentation xml:lang="en">
+                            Correlation ID value pattern.  This is a FreeMarker template, allowing
+                            construction of correlation IDs from BeanContext data.
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+				<xs:attribute name="routeOnElement" type="xs:string">
+					<xs:annotation>
+						<xs:documentation xml:lang="en">
+							The source element event on which to trigger routing of the bean.
+						</xs:documentation>
+					</xs:annotation>
+				</xs:attribute>
+            </xs:extension>
+        </xs:complexContent>
+	</xs:complexType>
+	
+	<xs:complexType name="to">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+				<xs:attribute name="endpoint" type="xs:string" use="required">
+					<xs:annotation>
+						<xs:documentation xml:lang="en">
+							The Camel endpoint to which the bean is to be routed.
+						</xs:documentation>
+					</xs:annotation>
+				</xs:attribute>
+				<xs:attribute name="if" type="xs:string">
+					<xs:annotation>
+						<xs:documentation xml:lang="en">
+							If condition.  Also supports adding of the condition on the child element.
+						</xs:documentation>
+					</xs:annotation>
+				</xs:attribute>
+                <xs:attribute name="correlationIdName" type="xs:string">
+                    <xs:annotation>
+                        <xs:documentation xml:lang="en">
+                            Endpoint specific correlation ID header name e.g. "JMSCorrelationID" when working
+                            with JMS components.  Allows override of the default correlationIdName set on the
+                            parent "route" element.
+                        </xs:documentation>
+                    </xs:annotation>
+                </xs:attribute>
+            </xs:extension>
+        </xs:simpleContent>
+	</xs:complexType>
+
+</xs:schema>
diff --git a/components/camel-smooks/src/main/resources/META-INF/xsd/smooks/camel-1.5.xsd-smooks.xml b/components/camel-smooks/src/main/resources/META-INF/xsd/smooks/camel-1.5.xsd-smooks.xml
new file mode 100644
index 00000000000..8d2ad52e58c
--- /dev/null
+++ b/components/camel-smooks/src/main/resources/META-INF/xsd/smooks/camel-1.5.xsd-smooks.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0"?>
+<!--
+
+    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.
+
+-->
+
+<smooks-resource-list xmlns="https://www.smooks.org/xsd/smooks-2.0.xsd"
+                      xmlns:camel="https://www.smooks.org/xsd/smooks/camel-1.5.xsd">
+
+    <resource-config selector="camel:route">
+        <resource>org.smooks.engine.resource.config.loader.xml.extension.NewResourceConfig</resource>
+        <param name="resource">org.apache.camel.component.smooks.routing.BeanRouter</param>
+        <param name="isTemplate">true</param>
+    </resource-config>
+    
+    <resource-config selector="camel:route">
+        <resource>org.smooks.engine.resource.config.loader.xml.extension.MapToResourceConfigFromAttribute</resource>
+        <param name="attribute">beanId</param>
+    </resource-config>
+
+    <resource-config selector="camel:route">
+        <resource>org.smooks.engine.resource.config.loader.xml.extension.MapToResourceConfigFromAttribute</resource>
+        <param name="attribute">routeOnElement</param>
+        <param name="mapTo">selector</param>
+    </resource-config>
+
+    <resource-config selector="camel:route">
+        <resource>org.smooks.engine.resource.config.loader.xml.extension.MapToResourceConfigFromAttribute</resource>
+        <param name="attribute">correlationIdName</param>
+        <param name="mapTo">correlationIdName</param>
+    </resource-config>
+
+    <resource-config selector="camel:route">
+        <resource>org.smooks.engine.resource.config.loader.xml.extension.MapToResourceConfigFromAttribute</resource>
+        <param name="attribute">correlationIdPattern</param>
+        <param name="mapTo">correlationIdPattern</param>
+    </resource-config>
+
+    <resource-config selector="camel:route/to">
+        <resource>org.smooks.engine.resource.config.loader.xml.extension.CloneResourceConfig</resource>
+    </resource-config>
+    
+    <resource-config selector="camel:route/to">
+        <resource>org.smooks.engine.resource.config.loader.xml.extension.MapToResourceConfigFromAttribute</resource>
+        <param name="attribute">endpoint</param>
+        <param name="mapTo">toEndpoint</param>
+    </resource-config>
+    
+    <resource-config selector="camel:route/to">
+        <resource>org.smooks.engine.resource.config.loader.xml.extension.MapToResourceConfigFromAttribute</resource>
+        <param name="attribute">if</param>
+        <param name="mapTo">condition</param>
+    </resource-config>
+    
+    <resource-config selector="camel:route/to">
+        <resource>org.smooks.engine.resource.config.loader.xml.extension.MapToResourceConfigFromText</resource>
+        <param name="mapTo">condition</param>
+    </resource-config>
+
+    <resource-config selector="camel:route/to">
+        <resource>org.smooks.engine.resource.config.loader.xml.extension.MapToResourceConfigFromAttribute</resource>
+        <param name="attribute">correlationIdName</param>
+        <param name="mapTo">correlationIdName</param>
+    </resource-config>
+
+</smooks-resource-list>
diff --git a/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/routing/BeanRouterFunctionalTest.java b/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/routing/BeanRouterFunctionalTest.java
new file mode 100644
index 00000000000..cfbe0af9454
--- /dev/null
+++ b/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/routing/BeanRouterFunctionalTest.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.component.smooks.routing;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.dataformat.smooks.Customer;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.smooks.Smooks;
+import org.smooks.io.source.StreamSource;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class BeanRouterFunctionalTest extends CamelTestSupport {
+    @Test
+    public void test() throws Exception {
+        MockEndpoint endpoint = createAndConfigureMockEndpoint("mock://beanRouterUnitTest");
+        endpoint.setExpectedMessageCount(1);
+
+        Smooks smooks = new Smooks("bean-routing-smooks-config.xml");
+        smooks.getApplicationContext().getRegistry().registerObject(CamelContext.class, endpoint.getCamelContext());
+        smooks.filterSource(new StreamSource<>(getClass().getResourceAsStream("/xml/customer.xml")));
+
+        endpoint.assertIsSatisfied();
+        Customer customer = endpoint.getReceivedExchanges().get(0).getMessage().getBody(Customer.class);
+        assertEquals("Wonderland", customer.getCountry());
+    }
+
+    private MockEndpoint createAndConfigureMockEndpoint(String endpointUri) throws Exception {
+        MockEndpoint mockEndpoint = getMockEndpoint(endpointUri);
+        return mockEndpoint;
+    }
+}
diff --git a/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/routing/BeanRouterObserverTest.java b/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/routing/BeanRouterObserverTest.java
new file mode 100644
index 00000000000..c96b307cfb8
--- /dev/null
+++ b/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/routing/BeanRouterObserverTest.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.smooks.routing;
+
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.smooks.api.bean.lifecycle.BeanContextLifecycleEvent;
+import org.smooks.api.bean.lifecycle.BeanLifecycle;
+import org.smooks.engine.bean.repository.DefaultBeanId;
+import org.smooks.testkit.MockExecutionContext;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Unit test for {@link BeanRouterObserver}
+ *
+ */
+public class BeanRouterObserverTest extends CamelTestSupport {
+    private static final String ENDPOINT_URI = "mock://beanRouterUnitTest";
+    private MockEndpoint endpoint;
+
+    @BeforeEach
+    public void beforeEach() {
+        endpoint = getMockEndpoint(ENDPOINT_URI);
+    }
+
+    @Test
+    public void onBeanLifecycleEventCreated() throws Exception {
+        final String sampleBean = "testOrder";
+        final String beanId = "orderId";
+        final BeanRouter beanRouter = new BeanRouter(context);
+
+        beanRouter.setBeanId(beanId);
+        beanRouter.setToEndpoint(ENDPOINT_URI);
+        beanRouter.postConstruct();
+
+        final BeanRouterObserver beanRouterObserver = new BeanRouterObserver(beanRouter, beanId);
+        final MockExecutionContext smooksExecutionContext = new MockExecutionContext();
+        final BeanContextLifecycleEvent event = mock(BeanContextLifecycleEvent.class);
+
+        when(event.getBeanId()).thenReturn(new DefaultBeanId(null, 0, beanId));
+        when(event.getLifecycle()).thenReturn(BeanLifecycle.END_FRAGMENT);
+        when(event.getBean()).thenReturn(sampleBean);
+        when(event.getExecutionContext()).thenReturn(smooksExecutionContext);
+
+        endpoint.setExpectedMessageCount(1);
+        beanRouterObserver.onBeanLifecycleEvent(event);
+        endpoint.assertIsSatisfied();
+        endpoint.expectedBodiesReceived(sampleBean);
+    }
+
+}
diff --git a/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/routing/BeanRouterTest.java b/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/routing/BeanRouterTest.java
new file mode 100644
index 00000000000..fcf3c435b3d
--- /dev/null
+++ b/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/routing/BeanRouterTest.java
@@ -0,0 +1,173 @@
+/*
+ * 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.routing;
+
+import java.util.Properties;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.component.smooks.SmooksConstants;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.smooks.Smooks;
+import org.smooks.api.ExecutionContext;
+import org.smooks.api.SmooksException;
+import org.smooks.api.bean.context.BeanContext;
+import org.smooks.api.bean.lifecycle.BeanLifecycle;
+import org.smooks.api.resource.config.ResourceConfig;
+import org.smooks.engine.bean.lifecycle.DefaultBeanContextLifecycleEvent;
+import org.smooks.engine.injector.Scope;
+import org.smooks.engine.lifecycle.PostConstructLifecyclePhase;
+import org.smooks.engine.lookup.LifecycleManagerLookup;
+import org.smooks.engine.resource.config.DefaultResourceConfig;
+import org.smooks.testkit.MockApplicationContext;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Unit test for {@link BeanRouter}.
+ *
+ */
+public class BeanRouterTest extends CamelTestSupport {
+    private static final String END_POINT_URI = "mock://beanRouterUnitTest";
+    private static final String BEAN_ID = "testBeanId";
+
+    private ExecutionContext smooksExecutionContext;
+    private MockEndpoint endpoint;
+    private MyBean myBean = new MyBean("bajja");
+    private BeanContext beanContext;
+
+    @Test
+    public void visitAfter() throws Exception {
+        endpoint.setExpectedMessageCount(1);
+        endpoint.expectedBodiesReceived(myBean);
+        createBeanRouter(BEAN_ID, END_POINT_URI).visitAfter(null, smooksExecutionContext);
+        endpoint.assertIsSatisfied();
+    }
+
+    @Test
+    public void testVisitAfterWithMissingBeanInSmookBeanContext() throws SmooksException {
+        when(beanContext.getBean(BEAN_ID)).thenReturn(null);
+        assertThrows(SmooksException.class,
+                () -> createBeanRouter(BEAN_ID, END_POINT_URI).visitAfter(null, smooksExecutionContext));
+    }
+
+    @Test
+    public void testBeanRouterUsingOnlyBeanId() throws Exception {
+        endpoint.setExpectedMessageCount(1);
+        endpoint.expectedBodiesReceived(myBean);
+
+        Smooks smooks = new Smooks();
+        ExecutionContext executionContext = smooks.createExecutionContext();
+
+        BeanRouter beanRouter = createBeanRouter(null, BEAN_ID, END_POINT_URI);
+        beanRouter.onPreExecution(executionContext);
+        executionContext.getBeanContext().addBean(BEAN_ID, myBean);
+
+        // Force an END event
+        executionContext.getBeanContext().notifyObservers(new DefaultBeanContextLifecycleEvent(
+                executionContext,
+                null, BeanLifecycle.END_FRAGMENT, executionContext.getBeanContext().getBeanId(BEAN_ID), myBean));
+
+        endpoint.assertIsSatisfied();
+    }
+
+    @Test
+    public void testBeanRouterAddsCamelSmooksExecutionContextHeader() throws Exception {
+        Smooks smooks = new Smooks();
+        ExecutionContext executionContext = smooks.createExecutionContext();
+
+        endpoint.setExpectedMessageCount(1);
+        endpoint.expectedHeaderReceived(SmooksConstants.SMOOKS_EXECUTION_CONTEXT, executionContext);
+
+        BeanRouter beanRouter = createBeanRouter(null, BEAN_ID, END_POINT_URI);
+        beanRouter.onPreExecution(executionContext);
+        executionContext.getBeanContext().addBean(BEAN_ID, myBean);
+
+        // Force an END event
+        executionContext.getBeanContext().notifyObservers(new DefaultBeanContextLifecycleEvent(
+                executionContext,
+                null, BeanLifecycle.END_FRAGMENT, executionContext.getBeanContext().getBeanId(BEAN_ID), myBean));
+
+        endpoint.assertIsSatisfied();
+        assertNotNull(endpoint.getReceivedExchanges().get(0).getMessage()
+                .getHeader(SmooksConstants.SMOOKS_EXECUTION_CONTEXT, ExecutionContext.class).getBeanContext().getBean(BEAN_ID));
+    }
+
+    @BeforeEach
+    public void beforeEach() throws Exception {
+        endpoint = createAndConfigureMockEndpoint(END_POINT_URI);
+        Exchange exchange = createExchange(endpoint);
+        BeanContext beanContext = createBeanContextAndSetBeanInContext(BEAN_ID, myBean);
+
+        smooksExecutionContext = createExecutionContext();
+        makeExecutionContextReturnBeanContext(beanContext);
+    }
+
+    private MockEndpoint createAndConfigureMockEndpoint(String endpointUri) throws Exception {
+        MockEndpoint mockEndpoint = getMockEndpoint(endpointUri);
+        return mockEndpoint;
+    }
+
+    private Exchange createExchange(MockEndpoint endpoint) {
+        Exchange exchange = endpoint.createExchange();
+        return exchange;
+    }
+
+    private BeanContext createBeanContextAndSetBeanInContext(String beanId, Object bean) {
+        beanContext = mock(BeanContext.class);
+        when(beanContext.getBean(beanId)).thenReturn(bean);
+        return beanContext;
+    }
+
+    private ExecutionContext createExecutionContext() {
+        return mock(ExecutionContext.class);
+    }
+
+    private void makeExecutionContextReturnBeanContext(BeanContext beanContext) {
+        when(smooksExecutionContext.getBeanContext()).thenReturn(beanContext);
+    }
+
+    private BeanRouter createBeanRouter(String beanId, String endpointUri) {
+        return createBeanRouter("dummySelector", beanId, endpointUri);
+    }
+
+    private BeanRouter createBeanRouter(String selector, String beanId, String endpointUri) {
+        BeanRouter beanRouter = new BeanRouter();
+        ResourceConfig resourceConfig = new DefaultResourceConfig();
+        if (selector != null) {
+            resourceConfig.setSelector(selector, new Properties());
+        }
+        resourceConfig.setParameter("beanId", beanId);
+        resourceConfig.setParameter("toEndpoint", endpointUri);
+
+        MockApplicationContext appContext = new MockApplicationContext();
+        appContext.getRegistry().registerObject(CamelContext.class, context);
+        appContext.getRegistry().lookup(new LifecycleManagerLookup()).applyPhase(beanRouter,
+                new PostConstructLifecyclePhase(new Scope(appContext.getRegistry(), resourceConfig, beanId)));
+
+        return beanRouter;
+    }
+
+    public record MyBean(String name) {
+    }
+}
diff --git a/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/routing/gender/Gender.java b/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/routing/gender/Gender.java
new file mode 100644
index 00000000000..18b4b123a92
--- /dev/null
+++ b/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/routing/gender/Gender.java
@@ -0,0 +1,22 @@
+/*
+ * 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.routing.gender;
+
+public enum Gender {
+    Male,
+    Female
+}
diff --git a/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/routing/gender/GenderTypeConverterFactory.java b/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/routing/gender/GenderTypeConverterFactory.java
new file mode 100644
index 00000000000..03fff88cb4a
--- /dev/null
+++ b/components/camel-smooks/src/test/java/org/apache/camel/component/smooks/routing/gender/GenderTypeConverterFactory.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.smooks.routing.gender;
+
+import org.smooks.api.converter.TypeConverter;
+import org.smooks.api.converter.TypeConverterDescriptor;
+import org.smooks.api.converter.TypeConverterFactory;
+import org.smooks.engine.converter.DefaultTypeConverterDescriptor;
+
+public class GenderTypeConverterFactory implements TypeConverterFactory<String, Gender> {
+    @Override
+    public TypeConverter<String, Gender> createTypeConverter() {
+        return value -> Enum.valueOf(Gender.class, value);
+    }
+
+    @Override
+    public TypeConverterDescriptor<Class<String>, Class<Gender>> getTypeConverterDescriptor() {
+        return new DefaultTypeConverterDescriptor<>(String.class, Gender.class);
+    }
+}
diff --git a/components/camel-smooks/src/test/java/org/apache/camel/dataformat/smooks/SmooksDataFormatTest.java b/components/camel-smooks/src/test/java/org/apache/camel/dataformat/smooks/SmooksDataFormatTest.java
index 0c58650fcc4..c7b3b9ed320 100644
--- a/components/camel-smooks/src/test/java/org/apache/camel/dataformat/smooks/SmooksDataFormatTest.java
+++ b/components/camel-smooks/src/test/java/org/apache/camel/dataformat/smooks/SmooksDataFormatTest.java
@@ -84,7 +84,7 @@ public class SmooksDataFormatTest extends CamelTestSupport {
         customer.setLastName("Cocktolstol");
         customer.setGender(Gender.Male);
         customer.setAge(35);
-        customer.setCountry("USA");
+        customer.setCountry("Wonderland");
 
         exchange.getIn().setBody(customer, JavaSource.class);
 
diff --git a/components/camel-smooks/src/test/resources/META-INF/services/org.smooks.api.converter.TypeConverterFactory b/components/camel-smooks/src/test/resources/META-INF/services/org.smooks.api.converter.TypeConverterFactory
new file mode 100644
index 00000000000..94a082822c7
--- /dev/null
+++ b/components/camel-smooks/src/test/resources/META-INF/services/org.smooks.api.converter.TypeConverterFactory
@@ -0,0 +1 @@
+org.apache.camel.component.smooks.routing.gender.GenderTypeConverterFactory
\ No newline at end of file
diff --git a/components/camel-smooks/src/test/resources/bean-routing-smooks-config.xml b/components/camel-smooks/src/test/resources/bean-routing-smooks-config.xml
new file mode 100644
index 00000000000..274b5cf6dd8
--- /dev/null
+++ b/components/camel-smooks/src/test/resources/bean-routing-smooks-config.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<!--
+
+    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.
+
+-->
+<smooks-resource-list
+        xmlns="https://www.smooks.org/xsd/smooks-2.0.xsd"
+        xmlns:jb="https://www.smooks.org/xsd/smooks/javabean-1.6.xsd"
+        xmlns:camel="https://www.smooks.org/xsd/smooks/camel-1.5.xsd">
+
+    <jb:bean beanId="cust" class="org.apache.camel.dataformat.smooks.Customer" createOnElement="customer">
+        <jb:value property="firstName" data="firstName"/>
+        <jb:value property="lastName" data="lastName"/>
+        <jb:value property="gender" data="gender"/>
+        <jb:value property="age" data="age"/>
+        <jb:value property="country" data="country"/>
+    </jb:bean>
+
+    <camel:route beanId="cust">
+        <camel:to endpoint="mock://beanRouterUnitTest" if="cust.country == 'Wonderland'"/>
+        <camel:to endpoint="mock://beanRouterUnitTest" if="cust.country == 'Narnia'"/>
+    </camel:route>
+
+</smooks-resource-list>
diff --git a/components/camel-smooks/src/test/resources/xml/customer.xml b/components/camel-smooks/src/test/resources/xml/customer.xml
index b4a3409d74c..007b19b0748 100644
--- a/components/camel-smooks/src/test/resources/xml/customer.xml
+++ b/components/camel-smooks/src/test/resources/xml/customer.xml
@@ -21,5 +21,5 @@
     <lastName>Cocktolstol</lastName>
     <gender>Male</gender>
     <age>35</age>
-    <country>USA</country>
+    <country>Wonderland</country>
 </customer>
diff --git a/components/camel-smooks/src/test/resources/xml/expected-customer.xml b/components/camel-smooks/src/test/resources/xml/expected-customer.xml
index dd5f71af8b9..a7cfe0e81a0 100644
--- a/components/camel-smooks/src/test/resources/xml/expected-customer.xml
+++ b/components/camel-smooks/src/test/resources/xml/expected-customer.xml
@@ -21,5 +21,5 @@
     <lastName>Cocktolstol</lastName>
     <gender>Male</gender>
     <age>35</age>
-    <country>USA</country>
+    <country>Wonderland</country>
 </org.apache.camel.dataformat.smooks.Customer>