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 2022/01/11 14:59:47 UTC

[camel] branch main updated: CAMEL-17468: camel-core - Filter EIP - add option to turn on exchange property with filter status

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 23ae746  CAMEL-17468: camel-core - Filter EIP - add option to turn on exchange property with filter status
23ae746 is described below

commit 23ae7466c8acdca657041ef24aa1700f809f0a69
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Jan 11 15:58:52 2022 +0100

    CAMEL-17468: camel-core - Filter EIP - add option to turn on exchange property with filter status
---
 .../main/docs/modules/eips/pages/filter-eip.adoc   | 32 ++++++++++++
 .../resources/org/apache/camel/model/filter.json   |  1 +
 .../org/apache/camel/model/FilterDefinition.java   | 22 ++++++++
 .../apache/camel/processor/FilterProcessor.java    | 12 +++++
 .../org/apache/camel/reifier/FilterReifier.java    |  7 ++-
 .../camel/processor/FilterStatusPropertyTest.java  | 61 ++++++++++++++++++++++
 .../java/org/apache/camel/xml/in/ModelParser.java  |  9 +++-
 .../dsl/yaml/deserializers/ModelDeserializers.java |  6 +++
 .../src/generated/resources/camel-yaml-dsl.json    |  3 ++
 9 files changed, 150 insertions(+), 3 deletions(-)

diff --git a/core/camel-core-engine/src/main/docs/modules/eips/pages/filter-eip.adoc b/core/camel-core-engine/src/main/docs/modules/eips/pages/filter-eip.adoc
index 9e05c29..15f2941 100644
--- a/core/camel-core-engine/src/main/docs/modules/eips/pages/filter-eip.adoc
+++ b/core/camel-core-engine/src/main/docs/modules/eips/pages/filter-eip.adoc
@@ -116,6 +116,38 @@ of the bean as shown:
 </route>
 ----
 
+=== Filtering with status property
+
+To know whether an `Exchange` was filtered or not, then you can choose to specify a name of a property
+to store on the exchange with the result (boolean), using `statusPropertyName` as shown below:
+
+[source,java]
+----
+from("direct:start")
+    .filter().method(MyBean.class, "isGoldCustomer").statusPropertyName("gold")
+      .to("mock:gold")
+    .end()
+    .to("mock:all");
+}
+----
+
+And in XML:
+
+[source,xml]
+----
+<route>
+    <from uri="direct:start"/>
+    <filter statusPropertyName="gold">
+        <method type="com.foo.MyBean" method="isGoldCustomer"/>
+        <to uri="mock:gold"/>
+    </filter>
+    <to uri="mock:all"/>
+</route>
+----
+
+In the example above then Camel will store an exchange property with key `gold` with the result of the filtering,
+whether it was `true` or `false`.
+
 === Filtering and stopping
 
 When using the Message Filter EIP, then it only applies to its children.
diff --git a/core/camel-core-model/src/generated/resources/org/apache/camel/model/filter.json b/core/camel-core-model/src/generated/resources/org/apache/camel/model/filter.json
index 173a586..31cefd5 100644
--- a/core/camel-core-model/src/generated/resources/org/apache/camel/model/filter.json
+++ b/core/camel-core-model/src/generated/resources/org/apache/camel/model/filter.json
@@ -13,6 +13,7 @@
   },
   "properties": {
     "expression": { "kind": "expression", "displayName": "Expression", "required": true, "type": "object", "javaType": "org.apache.camel.model.language.ExpressionDefinition", "oneOf": [ "constant", "csimple", "datasonnet", "exchangeProperty", "groovy", "header", "hl7terser", "joor", "jsonpath", "language", "method", "mvel", "ognl", "ref", "simple", "spel", "tokenize", "xpath", "xquery", "xtokenize" ], "deprecated": false, "autowired": false, "secret": false, "asPredicate": true, "descrip [...]
+    "statusPropertyName": { "kind": "attribute", "displayName": "Status Property Name", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "Name of exchange property to use for storing the status of the filtering. Setting this allows to know if the filter predicate evaluated as true or false." },
     "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/main/java/org/apache/camel/model/FilterDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/FilterDefinition.java
index 8f770fc..244339d 100644
--- a/core/camel-core-model/src/main/java/org/apache/camel/model/FilterDefinition.java
+++ b/core/camel-core-model/src/main/java/org/apache/camel/model/FilterDefinition.java
@@ -18,6 +18,7 @@ package org.apache.camel.model;
 
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlRootElement;
 
 import org.apache.camel.Predicate;
@@ -34,6 +35,9 @@ import org.apache.camel.spi.Metadata;
 @XmlAccessorType(XmlAccessType.FIELD)
 public class FilterDefinition extends OutputExpressionNode {
 
+    @XmlAttribute
+    private String statusPropertyName;
+
     public FilterDefinition() {
     }
 
@@ -60,6 +64,14 @@ public class FilterDefinition extends OutputExpressionNode {
         return "filter[" + getExpression() + "]";
     }
 
+    public String getStatusPropertyName() {
+        return statusPropertyName;
+    }
+
+    public void setStatusPropertyName(String statusPropertyName) {
+        this.statusPropertyName = statusPropertyName;
+    }
+
     /**
      * Expression to determine if the message should be filtered or not. If the expression returns an empty value or
      * <tt>false</tt> then the message is filtered (dropped), otherwise the message is continued being routed.
@@ -69,4 +81,14 @@ public class FilterDefinition extends OutputExpressionNode {
         // override to include javadoc what the expression is used for
         super.setExpression(expression);
     }
+
+    /**
+     * Name of exchange property to use for storing the status of the filtering.
+     *
+     * Setting this allows to know if the filter predicate evaluated as true or false.
+     */
+    public FilterDefinition statusPropertyName(String statusPropertyName) {
+        this.statusPropertyName = statusPropertyName;
+        return this;
+    }
 }
diff --git a/core/camel-core-processor/src/main/java/org/apache/camel/processor/FilterProcessor.java b/core/camel-core-processor/src/main/java/org/apache/camel/processor/FilterProcessor.java
index ae41e5b..5d66449 100644
--- a/core/camel-core-processor/src/main/java/org/apache/camel/processor/FilterProcessor.java
+++ b/core/camel-core-processor/src/main/java/org/apache/camel/processor/FilterProcessor.java
@@ -42,6 +42,7 @@ public class FilterProcessor extends DelegateAsyncProcessor implements Traceable
     private String routeId;
     private final Predicate predicate;
     private transient long filtered;
+    private String statusPropertyName;
 
     public FilterProcessor(CamelContext context, Predicate predicate, Processor processor) {
         super(processor);
@@ -49,6 +50,14 @@ public class FilterProcessor extends DelegateAsyncProcessor implements Traceable
         this.predicate = predicate;
     }
 
+    public String getStatusPropertyName() {
+        return statusPropertyName;
+    }
+
+    public void setStatusPropertyName(String statusPropertyName) {
+        this.statusPropertyName = statusPropertyName;
+    }
+
     @Override
     protected void doInit() throws Exception {
         super.doInit();
@@ -61,6 +70,9 @@ public class FilterProcessor extends DelegateAsyncProcessor implements Traceable
 
         try {
             matches = matches(exchange);
+            if (statusPropertyName != null) {
+                exchange.setProperty(statusPropertyName, matches);
+            }
         } catch (Exception e) {
             exchange.setException(e);
         }
diff --git a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/FilterReifier.java b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/FilterReifier.java
index 239a82b..5436386 100644
--- a/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/FilterReifier.java
+++ b/core/camel-core-reifier/src/main/java/org/apache/camel/reifier/FilterReifier.java
@@ -35,9 +35,14 @@ public class FilterReifier extends ExpressionReifier<FilterDefinition> {
 
     @Override
     protected FilterProcessor createFilterProcessor() throws Exception {
+        String status = parseString(definition.getStatusPropertyName());
+
         // filter EIP should have child outputs
         Processor childProcessor = this.createChildProcessor(true);
-        return new FilterProcessor(camelContext, createPredicate(), childProcessor);
+
+        FilterProcessor answer = new FilterProcessor(camelContext, createPredicate(), childProcessor);
+        answer.setStatusPropertyName(status);
+        return answer;
     }
 
 }
diff --git a/core/camel-core/src/test/java/org/apache/camel/processor/FilterStatusPropertyTest.java b/core/camel-core/src/test/java/org/apache/camel/processor/FilterStatusPropertyTest.java
new file mode 100644
index 0000000..9b1c054
--- /dev/null
+++ b/core/camel-core/src/test/java/org/apache/camel/processor/FilterStatusPropertyTest.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.processor;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+
+public class FilterStatusPropertyTest extends ContextTestSupport {
+
+    @Test
+    public void testSendMatchingMessage() throws Exception {
+        getMockEndpoint("mock:bar").expectedMessageCount(1);
+        getMockEndpoint("mock:bar").message(0).exchangeProperty("myBar").isEqualTo(true);
+        getMockEndpoint("mock:result").expectedMessageCount(1);
+        getMockEndpoint("mock:result").message(0).exchangeProperty("myBar").isEqualTo(true);
+
+        template.sendBodyAndHeader("direct:start", "<matched/>", "foo", "bar");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testSendNotMatchingMessage() throws Exception {
+        getMockEndpoint("mock:bar").expectedMessageCount(0);
+        getMockEndpoint("mock:result").expectedMessageCount(1);
+        getMockEndpoint("mock:result").message(0).exchangeProperty("myBar").isEqualTo(false);
+
+        template.sendBodyAndHeader("direct:start", "<notMatched/>", "foo", "notMatchedHeaderValue");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+                from("direct:start")
+                    .filter(header("foo").isEqualTo("bar")).statusPropertyName("myBar")
+                        .to("mock:bar")
+                    .end()
+                    .to("mock:result");
+            }
+        };
+    }
+
+}
diff --git a/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java b/core/camel-xml-io/src/generated/java/org/apache/camel/xml/in/ModelParser.java
index bf04ce6..49fbc89 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
@@ -403,8 +403,13 @@ public class ModelParser extends BaseParser {
         return doParse(new FaultToleranceConfigurationCommon(), faultToleranceConfigurationCommonAttributeHandler(),  noElementHandler(), noValueHandler());
     }
     protected FilterDefinition doParseFilterDefinition() throws IOException, XmlPullParserException {
-        return doParse(new FilterDefinition(),
-            processorDefinitionAttributeHandler(), outputExpressionNodeElementHandler(), noValueHandler());
+        return doParse(new FilterDefinition(), (def, key, val) -> {
+            if ("statusPropertyName".equals(key)) {
+                def.setStatusPropertyName(val);
+                return true;
+            }
+            return processorDefinitionAttributeHandler().accept(def, key, val);
+        }, outputExpressionNodeElementHandler(), noValueHandler());
     }
     protected <T extends OutputExpressionNode> ElementHandler<T> outputExpressionNodeElementHandler() {
         return (def, key) -> {
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 a3b978e..962193f 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
@@ -5142,6 +5142,7 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     @YamlProperty(name = "__extends", type = "object:org.apache.camel.model.language.ExpressionDefinition"),
                     @YamlProperty(name = "expression", type = "object:org.apache.camel.model.language.ExpressionDefinition"),
                     @YamlProperty(name = "inherit-error-handler", type = "boolean"),
+                    @YamlProperty(name = "status-property-name", type = "string"),
                     @YamlProperty(name = "steps", type = "array:org.apache.camel.model.ProcessorDefinition")
             }
     )
@@ -5169,6 +5170,11 @@ public final class ModelDeserializers extends YamlDeserializerSupport {
                     target.setInheritErrorHandler(java.lang.Boolean.valueOf(val));
                     break;
                 }
+                case "status-property-name": {
+                    String val = asText(node);
+                    target.setStatusPropertyName(val);
+                    break;
+                }
                 case "id": {
                     String val = asText(node);
                     target.setId(val);
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 08075c1..67eead4 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
@@ -913,6 +913,9 @@
           "inherit-error-handler" : {
             "type" : "boolean"
           },
+          "status-property-name" : {
+            "type" : "string"
+          },
           "steps" : {
             "type" : "array",
             "items" : {