This is an automated email from the ASF dual-hosted git repository. nfilotto pushed a commit to branch CAMEL-17755/replace-doswitch-with-choice-with-preco in repository https://gitbox.apache.org/repos/asf/camel.git
commit 26700c1ff1b48769e28710c375d87c9b8b8c8fb7 Author: Nicolas Filotto <nfilo...@talend.com> AuthorDate: Tue Mar 8 21:48:05 2022 +0100 CAMEL-17755: Propose precondition mode to Choice as replacement for DoSwitch --- .../org/apache/camel/catalog/models.properties | 1 - .../org/apache/camel/catalog/models/choice.json | 1 + .../org/apache/camel/catalog/models/doSwitch.json | 20 ---- .../apache/camel/catalog/schemas/camel-spring.xsd | 52 ++--------- .../docs/modules/eips/examples/json/doSwitch.json | 1 - .../src/main/docs/modules/eips/nav.adoc | 1 - .../main/docs/modules/eips/pages/choice-eip.adoc | 80 +++++++++++++++- .../main/docs/modules/eips/pages/switch-eip.adoc | 95 ------------------- .../services/org/apache/camel/model.properties | 1 - .../resources/org/apache/camel/model/choice.json | 1 + .../resources/org/apache/camel/model/doSwitch.json | 20 ---- .../resources/org/apache/camel/model/jaxb.index | 1 - .../org/apache/camel/model/ChoiceDefinition.java | 38 ++++++++ .../apache/camel/model/ProcessorDefinition.java | 12 --- .../org/apache/camel/model/SwitchDefinition.java | 44 --------- .../org/apache/camel/reifier/ChoiceReifier.java | 102 +++++++++++++++------ .../org/apache/camel/reifier/ProcessorReifier.java | 8 +- .../org/apache/camel/reifier/SwitchReifier.java | 96 ------------------- ...RouteTemplateChoiceInPreconditionModeTest.java} | 12 +-- ...Test.java => ChoiceInPreconditionModeTest.java} | 14 +-- .../java/org/apache/camel/xml/in/ModelParser.java | 21 ++--- .../ROOT/pages/camel-3x-upgrade-guide-3_16.adoc | 22 +++++ .../dsl/yaml/deserializers/ModelDeserializers.java | 74 ++------------- .../deserializers/ModelDeserializersResolver.java | 3 - .../src/generated/resources/camel-yaml-dsl.json | 38 +------- .../src/generated/resources/camelYamlDsl.json | 35 +------ .../org/apache/camel/dsl/yaml/ChoiceTest.groovy | 43 +++++++++ .../org/apache/camel/dsl/yaml/SwitchTest.groovy | 67 -------------- 28 files changed, 303 insertions(+), 600 deletions(-) diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties index 9ba8efe..0b9030c 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models.properties @@ -41,7 +41,6 @@ description dnsServiceDiscovery doCatch doFinally -doSwitch doTry dynamicRouter endpoint diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/choice.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/choice.json index eca6131..f666212 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/choice.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/choice.json @@ -14,6 +14,7 @@ "properties": { "when": { "kind": "element", "displayName": "When", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.WhenDefinition>", "oneOf": [ "when" ], "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "description": "Sets the when nodes" }, "otherwise": { "kind": "element", "displayName": "Otherwise", "required": false, "type": "object", "javaType": "org.apache.camel.model.OtherwiseDefinition", "oneOf": [ "otherwise" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the otherwise node" }, + "precondition": { "kind": "attribute", "displayName": "Precondition", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Indicates whether this Choice EIP is in precondition mode or not. If so its branches (when\/otherwise) are evaluated during startup to keep at runtime only the branch that matched." }, "id": { "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": { "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/doSwitch.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/doSwitch.json deleted file mode 100644 index a15cc5a..0000000 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/models/doSwitch.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "model": { - "kind": "model", - "name": "doSwitch", - "title": "Do Switch", - "description": "Route messages based on a series of predicates (optimized during startup to select one predicate that will always be used)", - "deprecated": false, - "label": "eip,routing", - "javaType": "org.apache.camel.model.SwitchDefinition", - "abstract": false, - "input": true, - "output": false - }, - "properties": { - "when": { "kind": "element", "displayName": "When", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.WhenDefinition>", "oneOf": [ "when" ], "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "description": "Sets the when nodes" }, - "otherwise": { "kind": "element", "displayName": "Otherwise", "required": false, "type": "object", "javaType": "org.apache.camel.model.OtherwiseDefinition", "oneOf": [ "otherwise" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the otherwise node" }, - "id": { "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": { "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/schemas/camel-spring.xsd b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/schemas/camel-spring.xsd index d06f7df..8c54a85 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 @@ -350,15 +350,6 @@ Path traversed when a try, catch, finally block exits </xs:annotation> </xs:element> - <xs:element name="doSwitch" type="tns:switchDefinition"> - <xs:annotation> - <xs:documentation xml:lang="en"><![CDATA[ -Route messages based on a series of predicates (optimized during startup to -select one predicate that will always be used) - ]]></xs:documentation> - </xs:annotation> - </xs:element> - <xs:element name="doTry" type="tns:tryDefinition"> <xs:annotation> <xs:documentation xml:lang="en"><![CDATA[ @@ -3053,7 +3044,6 @@ will fallback to use the fixed value if the Expression result was null or 0. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -3558,7 +3548,6 @@ should be intercepted by this exception type or not. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -3659,7 +3648,6 @@ should be intercepted by this exception type or not. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -3685,6 +3673,15 @@ should be intercepted by this exception type or not. <xs:element maxOccurs="unbounded" minOccurs="0" ref="tns:when"/> <xs:element minOccurs="0" ref="tns:otherwise"/> </xs:sequence> + <xs:attribute name="precondition" type="xs:string"> + <xs:annotation> + <xs:documentation xml:lang="en"><![CDATA[ +Indicates whether this Choice EIP is in precondition mode or not. If so its +branches (when/otherwise) are evaluated during startup to keep at runtime only +the branch that matched. Default value: false + ]]></xs:documentation> + </xs:annotation> + </xs:attribute> </xs:extension> </xs:complexContent> </xs:complexType> @@ -3748,7 +3745,6 @@ should be intercepted by this exception type or not. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -3829,7 +3825,6 @@ should be intercepted by this exception type or not. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -4876,7 +4871,6 @@ org.apache.camel.spi.SendDynamicAware . Default value: true <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -4962,7 +4956,6 @@ Setting this allows to know if the filter predicate evaluated as true or false. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -5102,7 +5095,6 @@ Global option value. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -5282,7 +5274,6 @@ Whether if validation is required for this input type. Default value: false <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -5376,7 +5367,6 @@ configured, then all incoming messages is intercepted. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -5477,7 +5467,6 @@ process its result. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -5572,7 +5561,6 @@ specified using uri syntax, eg mynamecount=4&type=gold. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -5867,7 +5855,6 @@ To refer to a custom logger instance to lookup from the registry. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -8902,7 +8889,6 @@ decompressed size. Default value: 1073741824 <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -9104,7 +9090,6 @@ should be invoked or not. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -9273,7 +9258,6 @@ failure. If this option is enabled then its considered handled as well. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -9636,7 +9620,6 @@ generate the log message from exchange. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -9774,7 +9757,6 @@ Include finding route builder from these java package names. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -9852,7 +9834,6 @@ Include finding route builder from these java package names. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -10397,7 +10378,6 @@ Name of property to remove. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -10703,7 +10683,6 @@ Reference to the routes in the xml dsl. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -11062,7 +11041,6 @@ compensation/completion exchange. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -11414,7 +11392,6 @@ Sets the comparator to use for sorting. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -11624,7 +11601,6 @@ individual unit of work. Default value: false <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -11651,14 +11627,6 @@ individual unit of work. Default value: false </xs:complexContent> </xs:complexType> - <xs:complexType name="switchDefinition"> - <xs:complexContent> - <xs:extension base="tns:choiceDefinition"> - <xs:sequence/> - </xs:extension> - </xs:complexContent> - </xs:complexType> - <xs:complexType name="templatedRouteBeanDefinition"> <xs:complexContent> <xs:extension base="tns:beanFactoryDefinition"> @@ -12126,7 +12094,6 @@ Whether to auto startup components when toD is starting up. Default value: true <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> @@ -12241,7 +12208,6 @@ Sets a reference to use for lookup the policy in the registry. <xs:element ref="tns:split"/> <xs:element ref="tns:step"/> <xs:element ref="tns:stop"/> - <xs:element ref="tns:doSwitch"/> <xs:element ref="tns:threads"/> <xs:element ref="tns:throttle"/> <xs:element ref="tns:throwException"/> diff --git a/core/camel-core-engine/src/main/docs/modules/eips/examples/json/doSwitch.json b/core/camel-core-engine/src/main/docs/modules/eips/examples/json/doSwitch.json deleted file mode 120000 index b0512c4..0000000 --- a/core/camel-core-engine/src/main/docs/modules/eips/examples/json/doSwitch.json +++ /dev/null @@ -1 +0,0 @@ -../../../../../../../../camel-core-model/src/generated/resources/org/apache/camel/model/doSwitch.json \ No newline at end of file diff --git a/core/camel-core-engine/src/main/docs/modules/eips/nav.adoc b/core/camel-core-engine/src/main/docs/modules/eips/nav.adoc index 54c5822..67a091a 100644 --- a/core/camel-core-engine/src/main/docs/modules/eips/nav.adoc +++ b/core/camel-core-engine/src/main/docs/modules/eips/nav.adoc @@ -82,7 +82,6 @@ ** xref:eips:split-eip.adoc[Split] ** xref:eips:step-eip.adoc[Step] ** xref:eips:stop-eip.adoc[Stop] - ** xref:eips:switch-eip.adoc[Switch] ** xref:eips:threads-eip.adoc[Threads] ** xref:eips:throttle-eip.adoc[Throttle] ** xref:eips:to-eip.adoc[To] diff --git a/core/camel-core-engine/src/main/docs/modules/eips/pages/choice-eip.adoc b/core/camel-core-engine/src/main/docs/modules/eips/pages/choice-eip.adoc index 0428e9b..550200a 100644 --- a/core/camel-core-engine/src/main/docs/modules/eips/pages/choice-eip.adoc +++ b/core/camel-core-engine/src/main/docs/modules/eips/pages/choice-eip.adoc @@ -144,6 +144,82 @@ There can be some combinations of xref:eips:enterprise-integration-patterns.adoc that can hit limits in how far we can take the fluent builder DSL with generics you can do in Java programming language. -== See Also +== Precondition Mode -See xref:switch-eip.adoc[Switch EIP]. \ No newline at end of file +In precondition mode, the Choice EIP is an optimized http://www.enterpriseintegrationpatterns.com/ContentBasedRouter.html[Content +Based Router] which selects a single branch (when/otherwise) during startup, and +always executes the same branch. This allows to optimize the runtime Camel to avoid +this evaluation process for every message; because they are supposed +to always be routed on the same branch. + +NOTE: Because the Choice EIP in precondition mode evaluates the predicates during startup, then the predicates +cannot be based on the content of the message. Therefore, the predicates would often +be based on property placeholders, JVM system properties, or OS Environment variables. + +The Choice EIP in precondition mode combined with xref:manual:ROOT:route-template.adoc[Route Templates] allows +for more flexible templates, as the template parameters can be used as the predicates in the Choice EIP; +meaning that the Choice EIP in precondition mode is fully parameterized, but is optimized for best runtime performance. + +=== Example + +The Camel xref:languages:simple-language.adoc[Simple] language +is great to use with the Choice EIP in precondition mode to select a specific branch based +on xref:manual:ROOT:using-propertyplaceholder.adoc[property placeholders]. + +Here we select from the Switch the first predicate that matches. So if there is +a property placeholder with the key `foo` then its select, and so on. +Notice how we can use `{{?foo}}` to mark the property placeholder as optional. + +[source,java] +---- +from("direct:a") + .choice().precondition() + .when(simple("{{?foo}}")).to("direct:foo") + .when(simple("{{?bar}}")).to("direct:bar") + .otherwise().to("direct:other"); +---- + +And the same example using XML DSL: + +[source,xml] +---- +<route> + <from uri="direct:a"/> + <choice precondition="true"> + <when> + <simple>{{?foo}}</simple> + <to uri="direct:foo"/> + </when> + <when> + <simple>{{?bar}}</simple> + <to uri="direct:bar"/> + </when> + <otherwise> + <to uri="direct:other"/> + </otherwise> + </choice> +</route> +---- + +And in YAML DS: + +[source,yaml] +---- +- from: + uri: "direct:a" + steps: + - choice: + precondition: true + when: + - simple: "{{?foo}}" + steps: + - to: "direct:foo" + - simple: "{{?bar}}" + steps: + - to: "direct:bar" + otherwise: + steps: + - to: "direct:other" +---- + +TIP: Otherwise, is optional, and if none of the predicates would match, then no branches is selected. \ No newline at end of file diff --git a/core/camel-core-engine/src/main/docs/modules/eips/pages/switch-eip.adoc b/core/camel-core-engine/src/main/docs/modules/eips/pages/switch-eip.adoc deleted file mode 100644 index f7ce625..0000000 --- a/core/camel-core-engine/src/main/docs/modules/eips/pages/switch-eip.adoc +++ /dev/null @@ -1,95 +0,0 @@ -= Switch EIP -:doctitle: Switch -:shortname: doSwitch -:description: Route messages based on a series of predicates -:since: -:supportlevel: Stable - -The Switch EIP is an optimized http://www.enterpriseintegrationpatterns.com/ContentBasedRouter.html[Content -Based Router] which selects a single branch (when/otherwise) during startup, and -always executes the same branch. This allows to optimize the runtime Camel to avoid -this evaluation process for every message; because they are supposed -to always be routed on the same branch. - -NOTE: Because the Switch EIP evaluates the predicates during startup, then the predicates -cannot be based on the content of the message. Therefore, the predicates would often -be based on property placeholders, JVM system properties, or OS Environment variables. - -The Switch EIP combined with xref:manual:ROOT:route-template.adoc[Route Templates] allows -for more flexible templates, as the template parameters can be used as the predicates in the Switch EIP; -meaning that the Switch EIP is fully parameterized, but is optimized for best runtime performance. - -image::eip/ContentBasedRouter.gif[image] - -== Switch options - -// eip options: START -include::partial$eip-options.adoc[] -// eip options: END - -== Example - -The Camel xref:languages:simple-language.adoc[Simple] language -is great to use with the Switch EIP to select a specific branch based -on xref:manual:ROOT:using-propertyplaceholder.adoc[property placeholders]. - -Here we select from the Switch the first predicate that matches. So if there is -a property placeholder with the key `foo` then its select, and so on. -Notice how we can use `{{?foo}}` to mark the property placeholder as optional. - -[source,java] ----- -from("direct:a") - .doSwitch() - .when(simple("{{?foo}}")).to("direct:foo") - .when(simple("{{?bar}}")).to("direct:bar") - .otherwise().to("direct:other"); ----- - -And the same example using XML DSL: - -[source,xml] ----- -<route> - <from uri="direct:a"/> - <doSwitch> - <when> - <simple>{{?foo}}</simple> - <to uri="direct:foo"/> - </when> - <when> - <simple>{{?bar}}</simple> - <to uri="direct:bar"/> - </when> - <otherwise> - <to uri="direct:other"/> - </otherwise> - </doSwitch> -</route> ----- - -And in YAML DS: - -[source,yaml] ----- -- from: - uri: "direct:a" - steps: - - doSwitch: - when: - - simple: "{{?foo}}" - steps: - - to: "direct:foo" - - simple: "{{?bar}}" - steps: - - to: "direct:bar" - otherwise: - steps: - - to: "direct:other" ----- - -TIP: Otherwise, is optional, and if none of the predicates would match, then no branches is selected. - -=== Why can I not use otherwise in Java DSL - -See the same section at xref:choice-eip.adoc[Choice EIP]. diff --git a/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties b/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties index acf74d0..812a961 100644 --- a/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties +++ b/core/camel-core-model/src/generated/resources/META-INF/services/org/apache/camel/model.properties @@ -39,7 +39,6 @@ description dnsServiceDiscovery doCatch doFinally -doSwitch doTry dynamicRouter enrich diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/choice.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/choice.json index eca6131..f666212 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/choice.json +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/choice.json @@ -14,6 +14,7 @@ "properties": { "when": { "kind": "element", "displayName": "When", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.WhenDefinition>", "oneOf": [ "when" ], "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "description": "Sets the when nodes" }, "otherwise": { "kind": "element", "displayName": "Otherwise", "required": false, "type": "object", "javaType": "org.apache.camel.model.OtherwiseDefinition", "oneOf": [ "otherwise" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the otherwise node" }, + "precondition": { "kind": "attribute", "displayName": "Precondition", "label": "advanced", "required": false, "type": "boolean", "javaType": "java.lang.Boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Indicates whether this Choice EIP is in precondition mode or not. If so its branches (when\/otherwise) are evaluated during startup to keep at runtime only the branch that matched." }, "id": { "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": { "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/doSwitch.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/doSwitch.json deleted file mode 100644 index a15cc5a..0000000 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/doSwitch.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "model": { - "kind": "model", - "name": "doSwitch", - "title": "Do Switch", - "description": "Route messages based on a series of predicates (optimized during startup to select one predicate that will always be used)", - "deprecated": false, - "label": "eip,routing", - "javaType": "org.apache.camel.model.SwitchDefinition", - "abstract": false, - "input": true, - "output": false - }, - "properties": { - "when": { "kind": "element", "displayName": "When", "required": false, "type": "array", "javaType": "java.util.List<org.apache.camel.model.WhenDefinition>", "oneOf": [ "when" ], "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "description": "Sets the when nodes" }, - "otherwise": { "kind": "element", "displayName": "Otherwise", "required": false, "type": "object", "javaType": "org.apache.camel.model.OtherwiseDefinition", "oneOf": [ "otherwise" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the otherwise node" }, - "id": { "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": { "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/jaxb.index b/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index index 6b088ff..592cf1a 100644 --- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index +++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/jaxb.index @@ -89,7 +89,6 @@ SortDefinition SplitDefinition StepDefinition StopDefinition -SwitchDefinition TemplatedRouteBeanDefinition TemplatedRouteDefinition TemplatedRouteParameterDefinition diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/ChoiceDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/ChoiceDefinition.java index 73801a5..38a9452 100644 --- a/core/camel-core-model/src/main/java/org/apache/camel/model/ChoiceDefinition.java +++ b/core/camel-core-model/src/main/java/org/apache/camel/model/ChoiceDefinition.java @@ -23,6 +23,7 @@ import java.util.stream.Collectors; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementRef; import javax.xml.bind.annotation.XmlRootElement; @@ -52,6 +53,9 @@ public class ChoiceDefinition extends ProcessorDefinition<ChoiceDefinition> impl @XmlElement @Metadata(description = "Sets the otherwise node") private OtherwiseDefinition otherwise; + @XmlAttribute + @Metadata(label = "advanced", javaType = "java.lang.Boolean", defaultValue = "false") + private String precondition; public ChoiceDefinition() { } @@ -147,6 +151,18 @@ public class ChoiceDefinition extends ProcessorDefinition<ChoiceDefinition> impl super.addOutput(output); } + public String getPrecondition() { + return precondition; + } + + /** + * Indicates whether this Choice EIP is in precondition mode or not. If so its branches (when/otherwise) are + * evaluated during startup to keep at runtime only the branch that matched. + */ + public void setPrecondition(String precondition) { + this.precondition = precondition; + } + @Override public ProcessorDefinition<?> end() { // we end a block so only when or otherwise is supported @@ -165,6 +181,28 @@ public class ChoiceDefinition extends ProcessorDefinition<ChoiceDefinition> impl // ------------------------------------------------------------------------- /** + * Indicates that this Choice EIP is in precondition mode, its branches (when/otherwise) are then evaluated during + * startup to keep at runtime only the branch that matched. + * + * @return the builder + */ + public ChoiceDefinition precondition() { + return precondition(true); + } + + /** + * Indicates whether this Choice EIP is in precondition mode or not. If so its branches (when/otherwise) are + * evaluated during startup to keep at runtime only the branch that matched. + * + * @param precondition the flag indicating if it is in precondition mode or not. + * @return the builder + */ + public ChoiceDefinition precondition(boolean precondition) { + setPrecondition(Boolean.toString(precondition)); + return this; + } + + /** * Sets the predicate for the when node * * @param predicate the predicate 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 e61d2ce..68ba1c1 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 @@ -1451,18 +1451,6 @@ public abstract class ProcessorDefinition<Type extends ProcessorDefinition<Type> } /** - * An optimized <a href="http://camel.apache.org/content-based-router.html">Content Based Router EIP:</a> Optimized - * during startup to select one predicate that will always be used. - * - * @return the builder for a switch expression - */ - public SwitchDefinition doSwitch() { - SwitchDefinition answer = new SwitchDefinition(); - addOutput(answer); - return answer; - } - - /** * Creates a try/catch block * * @return the builder for a tryBlock expression diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/SwitchDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/SwitchDefinition.java deleted file mode 100644 index 541a241..0000000 --- a/core/camel-core-model/src/main/java/org/apache/camel/model/SwitchDefinition.java +++ /dev/null @@ -1,44 +0,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. - */ -package org.apache.camel.model; - -import javax.xml.bind.annotation.XmlAccessType; -import javax.xml.bind.annotation.XmlAccessorType; -import javax.xml.bind.annotation.XmlRootElement; - -import org.apache.camel.spi.Metadata; - -/** - * Route messages based on a series of predicates (optimized during startup to select one predicate that will always be - * used) - */ -@Metadata(label = "eip,routing") -@XmlRootElement(name = "doSwitch") -@XmlAccessorType(XmlAccessType.FIELD) -public class SwitchDefinition extends ChoiceDefinition { - - @Override - public String toString() { - return "Switch[" + getWhenClauses() + (getOtherwise() != null ? " " + getOtherwise() : "") + "]"; - } - - @Override - public String getShortName() { - return "switch"; - } - -} diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ChoiceReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ChoiceReifier.java index dc99340..1be5abf 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ChoiceReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ChoiceReifier.java @@ -19,6 +19,7 @@ package org.apache.camel.reifier; import java.util.ArrayList; import java.util.List; +import org.apache.camel.Exchange; import org.apache.camel.ExpressionFactory; import org.apache.camel.Predicate; import org.apache.camel.Processor; @@ -30,43 +31,33 @@ import org.apache.camel.model.language.ExpressionDefinition; import org.apache.camel.processor.ChoiceProcessor; import org.apache.camel.processor.FilterProcessor; import org.apache.camel.spi.ExpressionFactoryAware; +import org.apache.camel.support.DefaultExchange; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ChoiceReifier extends ProcessorReifier<ChoiceDefinition> { + /** + * The logger. + */ + private static final Logger LOG = LoggerFactory.getLogger(ChoiceReifier.class); + public ChoiceReifier(Route route, ProcessorDefinition<?> definition) { super(route, ChoiceDefinition.class.cast(definition)); } @Override public Processor createProcessor() throws Exception { - List<FilterProcessor> filters = new ArrayList<>(); + final boolean isPrecondition = Boolean.TRUE == parseBoolean(definition.getPrecondition()); + final List<FilterProcessor> filters = isPrecondition ? null : new ArrayList<>(); for (WhenDefinition whenClause : definition.getWhenClauses()) { - ExpressionDefinition exp = whenClause.getExpression(); - if (exp.getExpressionType() != null) { - exp = exp.getExpressionType(); - } - Predicate pre = exp.getPredicate(); - if (pre instanceof ExpressionFactoryAware) { - ExpressionFactoryAware aware = (ExpressionFactoryAware) pre; - if (aware.getExpressionFactory() != null) { - // if using the Java DSL then the expression may have been - // set using the - // ExpressionClause (implements ExpressionFactoryAware) - // which is a fancy builder to define - // expressions and predicates - // using fluent builders in the DSL. However we need - // afterwards a callback to - // reset the expression to the expression type the - // ExpressionClause did build for us - ExpressionFactory model = aware.getExpressionFactory(); - if (model instanceof ExpressionDefinition) { - whenClause.setExpression((ExpressionDefinition) model); - } - } + initBranch(whenClause); + if (filters != null) { + filters.add((FilterProcessor) createProcessor(whenClause)); } - - FilterProcessor filter = (FilterProcessor) createProcessor(whenClause); - filters.add(filter); + } + if (isPrecondition) { + return getMatchingBranchProcessor(); } Processor otherwiseProcessor = null; if (definition.getOtherwise() != null) { @@ -75,4 +66,63 @@ public class ChoiceReifier extends ProcessorReifier<ChoiceDefinition> { return new ChoiceProcessor(filters, otherwiseProcessor); } + /** + * Initialize the given branch if needed. + */ + private void initBranch(WhenDefinition whenClause) { + ExpressionDefinition exp = whenClause.getExpression(); + if (exp.getExpressionType() != null) { + exp = exp.getExpressionType(); + } + Predicate pre = exp.getPredicate(); + if (pre instanceof ExpressionFactoryAware) { + ExpressionFactoryAware aware = (ExpressionFactoryAware) pre; + if (aware.getExpressionFactory() != null) { + // if using the Java DSL then the expression may have been + // set using the + // ExpressionClause (implements ExpressionFactoryAware) + // which is a fancy builder to define + // expressions and predicates + // using fluent builders in the DSL. However we need + // afterwards a callback to + // reset the expression to the expression type the + // ExpressionClause did build for us + ExpressionFactory model = aware.getExpressionFactory(); + if (model instanceof ExpressionDefinition) { + whenClause.setExpression((ExpressionDefinition) model); + } + } + } + } + + /** + * @return the processor corresponding to the matching branch if any, {@code null} otherwise. + */ + private Processor getMatchingBranchProcessor() throws Exception { + // evaluate when predicates to optimize + Exchange dummy = new DefaultExchange(camelContext); + for (WhenDefinition whenClause : definition.getWhenClauses()) { + ExpressionDefinition exp = whenClause.getExpression(); + exp.initPredicate(camelContext); + + Predicate predicate = exp.getPredicate(); + predicate.initPredicate(camelContext); + + boolean matches = predicate.matches(dummy); + if (matches) { + LOG.debug("doSwitch selected: {}", whenClause.getLabel()); + return createOutputsProcessor(whenClause.getOutputs()); + } + } + + if (definition.getOtherwise() != null) { + LOG.debug("doSwitch selected: otherwise"); + return createProcessor(definition.getOtherwise()); + } + + // no cases were selected + LOG.debug("doSwitch no when or otherwise selected"); + return null; + } + } diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java index 42695ca..1f6a3fe 100644 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java +++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/ProcessorReifier.java @@ -94,7 +94,6 @@ import org.apache.camel.model.SortDefinition; import org.apache.camel.model.SplitDefinition; import org.apache.camel.model.StepDefinition; import org.apache.camel.model.StopDefinition; -import org.apache.camel.model.SwitchDefinition; import org.apache.camel.model.ThreadsDefinition; import org.apache.camel.model.ThrottleDefinition; import org.apache.camel.model.ThrowExceptionDefinition; @@ -186,12 +185,7 @@ public abstract class ProcessorReifier<T extends ProcessorDefinition<?>> extends } else if (definition instanceof CatchDefinition) { return new CatchReifier(route, definition); } else if (definition instanceof ChoiceDefinition) { - if (definition instanceof SwitchDefinition) { - // switch is an optimized choice - return new SwitchReifier(route, definition); - } else { - return new ChoiceReifier(route, definition); - } + return new ChoiceReifier(route, definition); } else if (definition instanceof CircuitBreakerDefinition) { return new CircuitBreakerReifier(route, definition); } else if (definition instanceof ClaimCheckDefinition) { diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SwitchReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SwitchReifier.java deleted file mode 100644 index b160867..0000000 --- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/SwitchReifier.java +++ /dev/null @@ -1,96 +0,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. - */ -package org.apache.camel.reifier; - -import org.apache.camel.Exchange; -import org.apache.camel.ExpressionFactory; -import org.apache.camel.Predicate; -import org.apache.camel.Processor; -import org.apache.camel.Route; -import org.apache.camel.model.ProcessorDefinition; -import org.apache.camel.model.SwitchDefinition; -import org.apache.camel.model.WhenDefinition; -import org.apache.camel.model.language.ExpressionDefinition; -import org.apache.camel.spi.ExpressionFactoryAware; -import org.apache.camel.support.DefaultExchange; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class SwitchReifier extends ProcessorReifier<SwitchDefinition> { - - private static final Logger LOG = LoggerFactory.getLogger(SwitchReifier.class); - - public SwitchReifier(Route route, ProcessorDefinition<?> definition) { - super(route, SwitchDefinition.class.cast(definition)); - } - - @Override - public Processor createProcessor() throws Exception { - // prepare when predicates - for (WhenDefinition whenClause : definition.getWhenClauses()) { - ExpressionDefinition exp = whenClause.getExpression(); - if (exp.getExpressionType() != null) { - exp = exp.getExpressionType(); - } - Predicate pre = exp.getPredicate(); - if (pre instanceof ExpressionFactoryAware) { - ExpressionFactoryAware aware = (ExpressionFactoryAware) pre; - if (aware.getExpressionFactory() != null) { - // if using the Java DSL then the expression may have been - // set using the - // ExpressionClause (implements ExpressionFactoryAware) - // which is a fancy builder to define - // expressions and predicates - // using fluent builders in the DSL. However we need - // afterwards a callback to - // reset the expression to the expression type the - // ExpressionClause did build for us - ExpressionFactory model = aware.getExpressionFactory(); - if (model instanceof ExpressionDefinition) { - whenClause.setExpression((ExpressionDefinition) model); - } - } - } - } - - // evaluate when predicates to optimize - Exchange dummy = new DefaultExchange(camelContext); - for (WhenDefinition whenClause : definition.getWhenClauses()) { - ExpressionDefinition exp = whenClause.getExpression(); - exp.initPredicate(camelContext); - - Predicate predicate = exp.getPredicate(); - predicate.initPredicate(camelContext); - - boolean matches = predicate.matches(dummy); - if (matches) { - LOG.debug("doSwitch selected: {}", whenClause.getLabel()); - return createOutputsProcessor(whenClause.getOutputs()); - } - } - - if (definition.getOtherwise() != null) { - LOG.debug("doSwitch selected: otherwise"); - return createProcessor(definition.getOtherwise()); - } - - // no cases were selected - LOG.debug("doSwitch no when or otherwise selected"); - return null; - } - -} diff --git a/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateSwitchTest.java b/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateChoiceInPreconditionModeTest.java similarity index 91% rename from core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateSwitchTest.java rename to core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateChoiceInPreconditionModeTest.java index aef3a0a..557620f 100644 --- a/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateSwitchTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/builder/RouteTemplateChoiceInPreconditionModeTest.java @@ -19,10 +19,10 @@ package org.apache.camel.builder; import org.apache.camel.ContextTestSupport; import org.junit.jupiter.api.Test; -public class RouteTemplateSwitchTest extends ContextTestSupport { +class RouteTemplateChoiceInPreconditionModeTest extends ContextTestSupport { @Test - public void testRed() throws Exception { + void testRed() throws Exception { TemplatedRouteBuilder.builder(context, "myTemplate") .parameter("red", "true") .parameter("blue", "false") @@ -38,7 +38,7 @@ public class RouteTemplateSwitchTest extends ContextTestSupport { } @Test - public void testBlue() throws Exception { + void testBlue() throws Exception { TemplatedRouteBuilder.builder(context, "myTemplate") .parameter("red", "false") .parameter("blue", "true") @@ -54,7 +54,7 @@ public class RouteTemplateSwitchTest extends ContextTestSupport { } @Test - public void testNotProvidedBlue() throws Exception { + void testNotProvidedBlue() throws Exception { TemplatedRouteBuilder.builder(context, "myTemplate") .parameter("blue", "true") .routeId("myRoute") @@ -69,7 +69,7 @@ public class RouteTemplateSwitchTest extends ContextTestSupport { } @Test - public void testNotProvided() throws Exception { + void testNotProvided() throws Exception { TemplatedRouteBuilder.builder(context, "myTemplate") .routeId("myRoute") .add(); @@ -92,7 +92,7 @@ public class RouteTemplateSwitchTest extends ContextTestSupport { .templateOptionalParameter("red") .templateOptionalParameter("blue") .from("direct:start") - .doSwitch() + .choice().precondition() .when(simple("{{?red}}")).to("mock:red") .when(simple("{{?blue}}")).to("mock:blue") .end() diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/DoSwitchTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/ChoiceInPreconditionModeTest.java similarity index 93% rename from core/camel-core/src/test/java/org/apache/camel/processor/DoSwitchTest.java rename to core/camel-core/src/test/java/org/apache/camel/processor/ChoiceInPreconditionModeTest.java index f007e03..d6f3a8c 100644 --- a/core/camel-core/src/test/java/org/apache/camel/processor/DoSwitchTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/processor/ChoiceInPreconditionModeTest.java @@ -23,7 +23,7 @@ import org.apache.camel.builder.RouteBuilder; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -public class DoSwitchTest extends ContextTestSupport { +class ChoiceInPreconditionModeTest extends ContextTestSupport { @Override public boolean isUseRouteBuilder() { @@ -31,7 +31,7 @@ public class DoSwitchTest extends ContextTestSupport { } @Test - public void testRed() throws Exception { + void testRed() throws Exception { Properties init = new Properties(); init.setProperty("red", "true"); init.setProperty("blue", "false"); @@ -54,7 +54,7 @@ public class DoSwitchTest extends ContextTestSupport { } @Test - public void testBlue() throws Exception { + void testBlue() throws Exception { Properties init = new Properties(); init.setProperty("red", "false"); init.setProperty("blue", "true"); @@ -77,7 +77,7 @@ public class DoSwitchTest extends ContextTestSupport { } @Test - public void testYellow() throws Exception { + void testYellow() throws Exception { Properties init = new Properties(); init.setProperty("red", "false"); init.setProperty("blue", "false"); @@ -100,12 +100,12 @@ public class DoSwitchTest extends ContextTestSupport { } @Test - public void testNone() throws Exception { + void testNone() throws Exception { context.addRoutes(new RouteBuilder() { @Override public void configure() throws Exception { from("direct:start").routeId("myRoute") - .doSwitch().id("mySwitch") + .choice().precondition().id("mySwitch") .when(simple("{{?red}}")).to("mock:red").id("myRed") .when(simple("{{?blue}}")).to("mock:blue").id("myBlue") .end() @@ -132,7 +132,7 @@ public class DoSwitchTest extends ContextTestSupport { return new RouteBuilder() { public void configure() { from("direct:start").routeId("myRoute") - .doSwitch().id("mySwitch") + .choice().precondition(true).id("mySwitch") .when(simple("{{red}}")).to("mock:red").id("myRed") .when(simple("{{blue}}")).to("mock:blue").id("myBlue") .otherwise().to("mock:yellow").id("myYellow"); 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 4aaca5f..94bdffd 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 @@ -219,19 +219,21 @@ public class ModelParser extends BaseParser { return doParse(new WhenDefinition(), processorDefinitionAttributeHandler(), outputExpressionNodeElementHandler(), noValueHandler()); } - protected <T extends ChoiceDefinition> ElementHandler<T> choiceDefinitionElementHandler() { - return (def, key) -> { + protected ChoiceDefinition doParseChoiceDefinition() throws IOException, XmlPullParserException { + return doParse(new ChoiceDefinition(), (def, key, val) -> { + if ("precondition".equals(key)) { + def.setPrecondition(val); + return true; + } + return processorDefinitionAttributeHandler().accept(def, key, val); + }, (def, key) -> { switch (key) { case "when": doAdd(doParseWhenDefinition(), def.getWhenClauses(), def::setWhenClauses); break; case "otherwise": def.setOtherwise(doParseOtherwiseDefinition()); break; default: return optionalIdentifiedDefinitionElementHandler().accept(def, key); } return true; - }; - } - protected ChoiceDefinition doParseChoiceDefinition() throws IOException, XmlPullParserException { - return doParse(new ChoiceDefinition(), - processorDefinitionAttributeHandler(), choiceDefinitionElementHandler(), noValueHandler()); + }, noValueHandler()); } protected OtherwiseDefinition doParseOtherwiseDefinition() throws IOException, XmlPullParserException { return doParse(new OtherwiseDefinition(), @@ -1365,10 +1367,6 @@ public class ModelParser extends BaseParser { return doParse(new StopDefinition(), processorDefinitionAttributeHandler(), optionalIdentifiedDefinitionElementHandler(), noValueHandler()); } - protected SwitchDefinition doParseSwitchDefinition() throws IOException, XmlPullParserException { - return doParse(new SwitchDefinition(), - processorDefinitionAttributeHandler(), choiceDefinitionElementHandler(), noValueHandler()); - } protected TemplatedRouteBeanDefinition doParseTemplatedRouteBeanDefinition() throws IOException, XmlPullParserException { return doParse(new TemplatedRouteBeanDefinition(), beanFactoryDefinitionAttributeHandler(), beanFactoryDefinitionElementHandler(), noValueHandler()); @@ -3266,7 +3264,6 @@ public class ModelParser extends BaseParser { case "split": return doParseSplitDefinition(); case "step": return doParseStepDefinition(); case "stop": return doParseStopDefinition(); - case "doSwitch": return doParseSwitchDefinition(); case "threads": return doParseThreadsDefinition(); case "throttle": return doParseThrottleDefinition(); case "throwException": return doParseThrowExceptionDefinition(); diff --git a/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_16.adoc b/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_16.adoc index e6cde7c..c235b8f 100644 --- a/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_16.adoc +++ b/docs/user-manual/modules/ROOT/pages/camel-3x-upgrade-guide-3_16.adoc @@ -180,6 +180,28 @@ Removed some unnecessary methods in Java DSL. Renamed `executorServiceRef` to `executorService`. +=== DoSwitch EIP + +Replaced by Choice EIP in precondition mode. + +Before it was: +[source,java] +---- +.doSwitch() + .when(simple("{{?red}}")).to("mock:red") + .when(simple("{{?blue}}")).to("mock:blue") +.end() +---- + +Now it is: +[source,java] +---- +.choice().precondition() + .when(simple("{{?red}}")).to("mock:red") + .when(simple("{{?blue}}")).to("mock:blue") +.end() +---- + === Enrich & Poll Enrich EIPs Renamed `strategyRef` to `aggregationStrategy`, and marked this option as required. 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 34eb592..ab3c1f5 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 @@ -87,7 +87,6 @@ import org.apache.camel.model.SortDefinition; import org.apache.camel.model.SplitDefinition; import org.apache.camel.model.StepDefinition; import org.apache.camel.model.StopDefinition; -import org.apache.camel.model.SwitchDefinition; import org.apache.camel.model.TemplatedRouteParameterDefinition; import org.apache.camel.model.ThreadPoolProfileDefinition; import org.apache.camel.model.ThreadsDefinition; @@ -1674,6 +1673,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport { @YamlProperty(name = "id", type = "string"), @YamlProperty(name = "inherit-error-handler", type = "boolean"), @YamlProperty(name = "otherwise", type = "object:org.apache.camel.model.OtherwiseDefinition"), + @YamlProperty(name = "precondition", type = "boolean"), @YamlProperty(name = "steps", type = "array:org.apache.camel.model.ProcessorDefinition"), @YamlProperty(name = "when", type = "array:org.apache.camel.model.WhenDefinition") } @@ -1702,6 +1702,11 @@ public final class ModelDeserializers extends YamlDeserializerSupport { target.setOtherwise(val); break; } + case "precondition": { + String val = asText(node); + target.setPrecondition(val); + break; + } case "when": { java.util.List<org.apache.camel.model.WhenDefinition> val = asFlatList(node, org.apache.camel.model.WhenDefinition.class); target.setWhenClauses(val); @@ -15050,73 +15055,6 @@ public final class ModelDeserializers extends YamlDeserializerSupport { } @YamlType( - types = org.apache.camel.model.SwitchDefinition.class, - order = org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1, - nodes = { - "do-switch", - "doSwitch" - }, - properties = { - @YamlProperty(name = "description", type = "string"), - @YamlProperty(name = "id", type = "string"), - @YamlProperty(name = "inherit-error-handler", type = "boolean"), - @YamlProperty(name = "otherwise", type = "object:org.apache.camel.model.OtherwiseDefinition"), - @YamlProperty(name = "steps", type = "array:org.apache.camel.model.ProcessorDefinition"), - @YamlProperty(name = "when", type = "array:org.apache.camel.model.WhenDefinition") - } - ) - public static class SwitchDefinitionDeserializer extends YamlDeserializerBase<SwitchDefinition> { - public SwitchDefinitionDeserializer() { - super(SwitchDefinition.class); - } - - @Override - protected SwitchDefinition newInstance() { - return new SwitchDefinition(); - } - - @Override - protected boolean setProperty(SwitchDefinition target, String propertyKey, - String propertyName, Node node) { - switch(propertyKey) { - case "inherit-error-handler": { - String val = asText(node); - target.setInheritErrorHandler(java.lang.Boolean.valueOf(val)); - break; - } - case "otherwise": { - org.apache.camel.model.OtherwiseDefinition val = asType(node, org.apache.camel.model.OtherwiseDefinition.class); - target.setOtherwise(val); - break; - } - case "when": { - java.util.List<org.apache.camel.model.WhenDefinition> val = asFlatList(node, org.apache.camel.model.WhenDefinition.class); - target.setWhenClauses(val); - break; - } - case "id": { - String val = asText(node); - target.setId(val); - break; - } - case "description": { - org.apache.camel.model.DescriptionDefinition val = asType(node, org.apache.camel.model.DescriptionDefinition.class); - target.setDescription(val); - break; - } - case "steps": { - setSteps(target, node); - break; - } - default: { - return false; - } - } - return true; - } - } - - @YamlType( types = org.apache.camel.model.dataformat.SyslogDataFormat.class, order = org.apache.camel.dsl.yaml.common.YamlDeserializerResolver.ORDER_LOWEST - 1, nodes = "syslog", 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 24c2fa8..8011976 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 @@ -445,9 +445,6 @@ public final class ModelDeserializersResolver implements YamlDeserializerResolve case "org.apache.camel.model.StopDefinition": return new ModelDeserializers.StopDefinitionDeserializer(); case "stream-config": return new ModelDeserializers.StreamResequencerConfigDeserializer(); case "org.apache.camel.model.config.StreamResequencerConfig": return new ModelDeserializers.StreamResequencerConfigDeserializer(); - case "do-switch": return new ModelDeserializers.SwitchDefinitionDeserializer(); - case "doSwitch": return new ModelDeserializers.SwitchDefinitionDeserializer(); - case "org.apache.camel.model.SwitchDefinition": return new ModelDeserializers.SwitchDefinitionDeserializer(); case "syslog": return new ModelDeserializers.SyslogDataFormatDeserializer(); case "org.apache.camel.model.dataformat.SyslogDataFormat": return new ModelDeserializers.SyslogDataFormatDeserializer(); case "tar-file": return new ModelDeserializers.TarFileDataFormatDeserializer(); diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json index e7ac7f4..cdf77b0 100644 --- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json +++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camel-yaml-dsl.json @@ -236,12 +236,6 @@ "stop" : { "$ref" : "#/items/definitions/org.apache.camel.model.StopDefinition" }, - "do-switch" : { - "$ref" : "#/items/definitions/org.apache.camel.model.SwitchDefinition" - }, - "doSwitch" : { - "$ref" : "#/items/definitions/org.apache.camel.model.SwitchDefinition" - }, "threads" : { "$ref" : "#/items/definitions/org.apache.camel.model.ThreadsDefinition" }, @@ -628,6 +622,9 @@ "otherwise" : { "$ref" : "#/items/definitions/org.apache.camel.model.OtherwiseDefinition" }, + "precondition" : { + "type" : "boolean" + }, "steps" : { "type" : "array", "items" : { @@ -2950,35 +2947,6 @@ } } }, - "org.apache.camel.model.SwitchDefinition" : { - "type" : "object", - "properties" : { - "description" : { - "type" : "string" - }, - "id" : { - "type" : "string" - }, - "inherit-error-handler" : { - "type" : "boolean" - }, - "otherwise" : { - "$ref" : "#/items/definitions/org.apache.camel.model.OtherwiseDefinition" - }, - "steps" : { - "type" : "array", - "items" : { - "$ref" : "#/items/definitions/org.apache.camel.model.ProcessorDefinition" - } - }, - "when" : { - "type" : "array", - "items" : { - "$ref" : "#/items/definitions/org.apache.camel.model.WhenDefinition" - } - } - } - }, "org.apache.camel.model.TemplatedRouteBeanDefinition" : { "type" : "object", "properties" : { diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camelYamlDsl.json b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camelYamlDsl.json index 7179ecf..f0628b0 100644 --- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camelYamlDsl.json +++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/generated/resources/camelYamlDsl.json @@ -161,9 +161,6 @@ "stop" : { "$ref" : "#/items/definitions/org.apache.camel.model.StopDefinition" }, - "doSwitch" : { - "$ref" : "#/items/definitions/org.apache.camel.model.SwitchDefinition" - }, "threads" : { "$ref" : "#/items/definitions/org.apache.camel.model.ThreadsDefinition" }, @@ -532,6 +529,9 @@ "otherwise" : { "$ref" : "#/items/definitions/org.apache.camel.model.OtherwiseDefinition" }, + "precondition" : { + "type" : "boolean" + }, "steps" : { "type" : "array", "items" : { @@ -2851,35 +2851,6 @@ } } }, - "org.apache.camel.model.SwitchDefinition" : { - "type" : "object", - "properties" : { - "description" : { - "type" : "string" - }, - "id" : { - "type" : "string" - }, - "inheritErrorHandler" : { - "type" : "boolean" - }, - "otherwise" : { - "$ref" : "#/items/definitions/org.apache.camel.model.OtherwiseDefinition" - }, - "steps" : { - "type" : "array", - "items" : { - "$ref" : "#/items/definitions/org.apache.camel.model.ProcessorDefinition" - } - }, - "when" : { - "type" : "array", - "items" : { - "$ref" : "#/items/definitions/org.apache.camel.model.WhenDefinition" - } - } - } - }, "org.apache.camel.model.TemplatedRouteBeanDefinition" : { "type" : "object", "properties" : { diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/ChoiceTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/ChoiceTest.groovy index 9595c5b..4ae8a5f 100644 --- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/ChoiceTest.groovy +++ b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/ChoiceTest.groovy @@ -65,4 +65,47 @@ class ChoiceTest extends YamlTestSupport { } } } + + def "choice in precondition mode"() { + when: + loadRoutes ''' + - from: + uri: "direct:start" + steps: + - choice: + precondition: true + when: + - simple: "{{?red}}" + steps: + - to: "mock:red" + - simple: "{{?blue}}" + steps: + - to: "mock:blue" + otherwise: + steps: + - to: "mock:other" + ''' + then: + context.routeDefinitions.size() == 1 + + with(context.routeDefinitions[0].outputs[0], ChoiceDefinition) { + with(whenClauses[0], WhenDefinition) { + expression.language == 'simple' + expression.expression == '{{?red}}' + with(outputs[0], ToDefinition) { + endpointUri == 'mock:red' + } + } + with(whenClauses[1], WhenDefinition) { + expression.language == 'simple' + expression.expression == '{{?blue}}' + with(outputs[0], ToDefinition) { + endpointUri == 'mock:blue' + } + } + with(otherwise.outputs[0], ToDefinition) { + endpointUri == 'mock:other' + } + } + } } diff --git a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/SwitchTest.groovy b/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/SwitchTest.groovy deleted file mode 100644 index 2d5730c..0000000 --- a/dsl/camel-yaml-dsl/camel-yaml-dsl/src/test/groovy/org/apache/camel/dsl/yaml/SwitchTest.groovy +++ /dev/null @@ -1,67 +0,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. - */ -package org.apache.camel.dsl.yaml - -import org.apache.camel.dsl.yaml.support.YamlTestSupport -import org.apache.camel.model.SwitchDefinition -import org.apache.camel.model.ToDefinition -import org.apache.camel.model.WhenDefinition - -class SwitchTest extends YamlTestSupport { - - def "switch definition"() { - when: - loadRoutes ''' - - from: - uri: "direct:start" - steps: - - doSwitch: - when: - - simple: "{{?red}}" - steps: - - to: "mock:red" - - simple: "{{?blue}}" - steps: - - to: "mock:blue" - otherwise: - steps: - - to: "mock:other" - ''' - then: - context.routeDefinitions.size() == 1 - - with(context.routeDefinitions[0].outputs[0], SwitchDefinition) { - with(whenClauses[0], WhenDefinition) { - expression.language == 'simple' - expression.expression == '{{?red}}' - with(outputs[0], ToDefinition) { - endpointUri == 'mock:red' - } - } - with(whenClauses[1], WhenDefinition) { - expression.language == 'simple' - expression.expression == '{{?blue}}' - with(outputs[0], ToDefinition) { - endpointUri == 'mock:blue' - } - } - with(otherwise.outputs[0], ToDefinition) { - endpointUri == 'mock:other' - } - } - } -}