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 2018/02/06 14:01:37 UTC

[camel] branch 8958 updated (a1b419b -> 5dc0f47)

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a change to branch 8958
in repository https://gitbox.apache.org/repos/asf/camel.git.


    from a1b419b  CAMEL-8958: Claim Check EIP with push/pop. Work in progress.
     new c135f44  CAMEL-8958: Claim Check EIP with push/pop. Work in progress.
     new e0d71c4  CAMEL-8958: Claim Check EIP with push/pop. Work in progress.
     new 5dc0f47  CAMEL-8958: Polished

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 camel-core/src/main/docs/eips/claimCheck-eip.adoc  |  61 +++--
 camel-core/src/main/docs/eips/hystrix-eip.adoc     |   2 +-
 .../apache/camel/model/ClaimCheckDefinition.java   | 105 ++++----
 .../apache/camel/model/ProcessorDefinition.java    |  25 +-
 .../processor/ClaimCheckAggregationStrategy.java   | 265 +++++++++++++++------
 .../camel/processor/ClaimCheckProcessor.java       |  22 +-
 .../ClaimCheckEipPushPopExcludeBodyTest.java       |   6 +-
 ...a => ClaimCheckEipPushPopRemoveHeaderTest.java} |  12 +-
 ...pringClaimCheckEipPushPopRemoveHeaderTest.java} |   6 +-
 .../processor/ClaimCheckEipPushPopBodyTest.xml     |   2 +-
 .../ClaimCheckEipPushPopHeadersPatternTest.xml     |   2 +-
 .../processor/ClaimCheckEipPushPopHeadersTest.xml  |   2 +-
 ...ml => ClaimCheckEipPushPopRemoveHeaderTest.xml} |   9 +-
 13 files changed, 333 insertions(+), 186 deletions(-)
 copy camel-core/src/test/java/org/apache/camel/processor/{ClaimCheckEipPushPopExcludeBodyTest.java => ClaimCheckEipPushPopRemoveHeaderTest.java} (83%)
 copy components/camel-spring/src/test/java/org/apache/camel/spring/processor/{SpringClaimCheckEipPushPopHeadersTest.java => SpringClaimCheckEipPushPopRemoveHeaderTest.java} (82%)
 copy components/camel-spring/src/test/resources/org/apache/camel/spring/processor/{ClaimCheckEipPushPopBodyTest.xml => ClaimCheckEipPushPopRemoveHeaderTest.xml} (84%)

-- 
To stop receiving notification emails like this one, please contact
davsclaus@apache.org.

[camel] 03/03: CAMEL-8958: Polished

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch 8958
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 5dc0f47a008011573c0a742add1899f933e594a4
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Feb 6 14:50:45 2018 +0100

    CAMEL-8958: Polished
---
 camel-core/src/main/docs/eips/claimCheck-eip.adoc | 2 +-
 camel-core/src/main/docs/eips/hystrix-eip.adoc    | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/camel-core/src/main/docs/eips/claimCheck-eip.adoc b/camel-core/src/main/docs/eips/claimCheck-eip.adoc
index 4a505ca..3b52ea2 100644
--- a/camel-core/src/main/docs/eips/claimCheck-eip.adoc
+++ b/camel-core/src/main/docs/eips/claimCheck-eip.adoc
@@ -1,7 +1,7 @@
 [[claimCheck-eip]]
 == Claim Check EIP
 
-Available as of Camel 2.21
+*Available as of Camel 2.21*
 
 The Claim Check EIP allows you to replace message content with a claim check (a unique key),
 which can be used to retrieve the message content at a later time.
diff --git a/camel-core/src/main/docs/eips/hystrix-eip.adoc b/camel-core/src/main/docs/eips/hystrix-eip.adoc
index 3cfd897..fd598ad 100644
--- a/camel-core/src/main/docs/eips/hystrix-eip.adoc
+++ b/camel-core/src/main/docs/eips/hystrix-eip.adoc
@@ -1,7 +1,7 @@
 [[hystrix-eip]]
 == Hystrix EIP
 
-Available as of Camel 2.18
+*Available as of Camel 2.18*
 
 The Hystrix EIP provides integration with Netflix link:https://github.com/Netflix/Hystrix[Hystrix] to be used as circuit breaker in the Camel routes. Hystrix is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable.
 

-- 
To stop receiving notification emails like this one, please contact
davsclaus@apache.org.

[camel] 02/03: CAMEL-8958: Claim Check EIP with push/pop. Work in progress.

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch 8958
in repository https://gitbox.apache.org/repos/asf/camel.git

commit e0d71c494b6dccef22f6055108ae7e142e287cc0
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Feb 6 14:46:04 2018 +0100

    CAMEL-8958: Claim Check EIP with push/pop. Work in progress.
---
 camel-core/src/main/docs/eips/claimCheck-eip.adoc  | 59 ++++++++++++++++------
 ...SpringClaimCheckEipPushPopRemoveHeaderTest.java | 29 +++++++++++
 .../processor/ClaimCheckEipPushPopBodyTest.xml     |  2 +-
 .../ClaimCheckEipPushPopHeadersPatternTest.xml     |  2 +-
 .../processor/ClaimCheckEipPushPopHeadersTest.xml  |  2 +-
 ...ml => ClaimCheckEipPushPopRemoveHeaderTest.xml} |  9 +++-
 6 files changed, 83 insertions(+), 20 deletions(-)

diff --git a/camel-core/src/main/docs/eips/claimCheck-eip.adoc b/camel-core/src/main/docs/eips/claimCheck-eip.adoc
index a0ff103..4a505ca 100644
--- a/camel-core/src/main/docs/eips/claimCheck-eip.adoc
+++ b/camel-core/src/main/docs/eips/claimCheck-eip.adoc
@@ -12,7 +12,7 @@ NOTE: The Camel implementation of this EIP pattern stores the message content te
 
 
 // eip options: START
-The Claim Check EIP supports 6 options which are listed below:
+The Claim Check EIP supports 5 options which are listed below:
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -20,8 +20,7 @@ The Claim Check EIP supports 6 options which are listed below:
 | Name | Description | Default | Type
 | *operation* | *Required* The claim check operation to use. The following operations is supported: Get - Gets (does not remove) the claim check by the given key. GetAndRemove - Gets and remove the claim check by the given key. Set - Sets a new (will override if key already exists) claim check with the given key. Push - Sets a new claim check on the stack (does not use key). Pop - Gets the latest claim check from the stack (does not use key). |  | ClaimCheckOperation
 | *key* | To use a specific key for claim check id. |  | String
-| *include* | What data to include when merging data back from claim check repository. The following syntax is supported: body - to aggregate the message body headers - to aggregate all the message headers header:pattern - to aggregate all the message headers that matches the pattern. The pattern syntax is documented by: link EndpointHelpermatchPattern(String String). You can specify multiple rules separated by comma. For example to include the message body and all headers starting with  [...]
-| *exclude* | What data to exclude when merging data back from claim check repository. The following syntax is supported: body - to aggregate the message body headers - to aggregate all the message headers header:pattern - to aggregate all the message headers that matches the pattern. The pattern syntax is documented by: link EndpointHelpermatchPattern(String String). You can specify multiple rules separated by comma. For example to exclude the message body and all headers starting with  [...]
+| *filter* | Specified a filter to control what data gets merging data back from the claim check repository. The following syntax is supported: body - to aggregate the message body headers - to aggregate all the message headers header:pattern - to aggregate all the message headers that matches the pattern. The pattern syntax is documented by: link EndpointHelpermatchPattern(String String). You can specify multiple rules separated by comma. For example to include the message body and all  [...]
 | *strategyRef* | To use a custom AggregationStrategy instead of the default implementation. Notice you cannot use both custom aggregation strategy and configure data at the same time. |  | String
 | *strategyMethodName* | This option can be used to explicit declare the method name to use when using POJOs as the AggregationStrategy. |  | String
 |===
@@ -44,24 +43,26 @@ These operations will then store and retrieve the data using this key. You can u
 The `Push` and `Pop` operations do *not* use a key but stores the data in a stack structure.
 
 
-=== What data to merge back
+=== Filter what data to merge back
 
-The `data` option is used to define what data to merge back when using the `Get` or `Pop` operation. When data is merged back
-then its merged using a `AggregationStrategy`. The default strategy uses the `data` option to easily specify what data to merge back.
+The `filter` option is used to define what data to merge back when using the `Get` or `Pop` operation. When data is merged back
+then its merged using a `AggregationStrategy`. The default strategy uses the `filter` option to easily specify what data to merge back.
 
-The `data` option takes a String value with the following syntax:
+The `filter` option takes a `String` value with the following syntax:
 
-* body - to aggregate the message body
-* headers - to aggregate all the message headers
-* header:pattern - to aggregate all the message headers that matches the pattern.
+* `body` = to aggregate the message body
+* `headers` = to aggregate all the message headers
+* `header:pattern` = to aggregate all the message headers that matches the pattern.
 
 The pattern rule supports wildcard and regular expression:
 
-* wildcard match (pattern ends with a * and the name starts with the pattern)
+* wildcard match (pattern ends with a `*` and the name starts with the pattern)
 * regular expression match
 
 You can specify multiple rules separated by comma.
 
+==== Basic filter examples
+
 For example to include the message body and all headers starting with _foo_:
 
 [text]
@@ -90,9 +91,34 @@ To only merge back a header name foo:
 header:foo
 ----
 
-If the data rule is specified as empty or as wildcard then everything is merged.
+If the filter rule is specified as empty or as wildcard then everything is merged.
+
+Notice that when merging back data, then any existing data is overwritten, and any other existing data is preserved.
+
+==== Fine grained filtering with include and explude pattern
+
+The syntax also supports the following prefixes which can be used to specify include,exclude, or remove
+
+* `+` = to include (which is the default mode)
+* `-` = to exclude (exclude takes precedence over include)
+* `--` = to remove (remove takes precedence)
+
+For example to skip the message body, and merge back everything else
+----
+-body
+----
+
+Or to skip the message header foo, and merge back everything else
+----
+-header:foo
+----
+
+You can also instruct to remove headers when merging data back, for example to remove all headers starting with _bar_:
+----
+--headers:bar*
+----
 
-Notice that when merging back data, then any existing data is overriden, and any other existing data is preserved.
+Note you cannot have both include (`+`) and exclude (`-`) `header:pattern` at the same time.
 
 
 === Java Examples
@@ -134,7 +160,7 @@ from("direct:start")
 Notice how we can `Get` the same data twice using the `Get` operation as it will not remove the data. If you only want
 to get the data once, you can use `GetAndRemove`.
 
-The last example shows how to use the `data` option where we only want to get back header named `foo` or `bar`:
+The last example shows how to use the `filter` option where we only want to get back header named `foo` or `bar`:
 
 [java]
 ----
@@ -199,7 +225,7 @@ Here is an example using `Get` and `Set` operations, which uses the key `foo`:
 Notice how we can `Get` the same data twice using the `Get` operation as it will not remove the data. If you only want
 to get the data once, you can use `GetAndRemove`.
 
-The last example shows how to use the `data` option where we only want to get back header named `foo` or `bar`:
+The last example shows how to use the `filter` option where we only want to get back header named `foo` or `bar`:
 
 [xml]
 ----
@@ -215,7 +241,8 @@ The last example shows how to use the `data` option where we only want to get ba
   </setHeader>
   <removeHeader headerName="bar"/>
   <to uri="mock:b"/>
-  <claimCheck operation="Pop" data="header:(foo|bar)"/>
+  <!-- only merge in the message headers foo or bar -->
+  <claimCheck operation="Pop" filter="header:(foo|bar)"/>
   <to uri="mock:c"/>
 </route>
 ----
diff --git a/components/camel-spring/src/test/java/org/apache/camel/spring/processor/SpringClaimCheckEipPushPopRemoveHeaderTest.java b/components/camel-spring/src/test/java/org/apache/camel/spring/processor/SpringClaimCheckEipPushPopRemoveHeaderTest.java
new file mode 100644
index 0000000..15bdb20
--- /dev/null
+++ b/components/camel-spring/src/test/java/org/apache/camel/spring/processor/SpringClaimCheckEipPushPopRemoveHeaderTest.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.spring.processor;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.processor.ClaimCheckEipPushPopRemoveHeaderTest;
+
+import static org.apache.camel.spring.processor.SpringTestHelper.createSpringCamelContext;
+
+public class SpringClaimCheckEipPushPopRemoveHeaderTest extends ClaimCheckEipPushPopRemoveHeaderTest {
+
+    protected CamelContext createCamelContext() throws Exception {
+        return createSpringCamelContext(this, "org/apache/camel/spring/processor/ClaimCheckEipPushPopRemoveHeaderTest.xml");
+    }
+}
\ No newline at end of file
diff --git a/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/ClaimCheckEipPushPopBodyTest.xml b/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/ClaimCheckEipPushPopBodyTest.xml
index e4e2661..d6c53ad 100644
--- a/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/ClaimCheckEipPushPopBodyTest.xml
+++ b/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/ClaimCheckEipPushPopBodyTest.xml
@@ -36,7 +36,7 @@
         <constant>456</constant>
       </setHeader>
       <to uri="mock:b"/>
-      <claimCheck operation="Pop" include="body"/>
+      <claimCheck operation="Pop" filter="body"/>
       <to uri="mock:c"/>
     </route>
   </camelContext>
diff --git a/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/ClaimCheckEipPushPopHeadersPatternTest.xml b/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/ClaimCheckEipPushPopHeadersPatternTest.xml
index 13eb12e..6efad19 100644
--- a/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/ClaimCheckEipPushPopHeadersPatternTest.xml
+++ b/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/ClaimCheckEipPushPopHeadersPatternTest.xml
@@ -37,7 +37,7 @@
       </setHeader>
       <removeHeader headerName="bar"/>
       <to uri="mock:b"/>
-      <claimCheck operation="Pop" include="header:(foo|bar)"/>
+      <claimCheck operation="Pop" filter="header:(foo|bar)"/>
       <to uri="mock:c"/>
     </route>
   </camelContext>
diff --git a/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/ClaimCheckEipPushPopHeadersTest.xml b/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/ClaimCheckEipPushPopHeadersTest.xml
index e56be5e..a0deac7 100644
--- a/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/ClaimCheckEipPushPopHeadersTest.xml
+++ b/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/ClaimCheckEipPushPopHeadersTest.xml
@@ -36,7 +36,7 @@
         <constant>456</constant>
       </setHeader>
       <to uri="mock:b"/>
-      <claimCheck operation="Pop" include="headers"/>
+      <claimCheck operation="Pop" filter="headers"/>
       <to uri="mock:c"/>
     </route>
   </camelContext>
diff --git a/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/ClaimCheckEipPushPopBodyTest.xml b/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/ClaimCheckEipPushPopRemoveHeaderTest.xml
similarity index 84%
copy from components/camel-spring/src/test/resources/org/apache/camel/spring/processor/ClaimCheckEipPushPopBodyTest.xml
copy to components/camel-spring/src/test/resources/org/apache/camel/spring/processor/ClaimCheckEipPushPopRemoveHeaderTest.xml
index e4e2661..752f2d1 100644
--- a/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/ClaimCheckEipPushPopBodyTest.xml
+++ b/components/camel-spring/src/test/resources/org/apache/camel/spring/processor/ClaimCheckEipPushPopRemoveHeaderTest.xml
@@ -27,6 +27,9 @@
   <camelContext xmlns="http://camel.apache.org/schema/spring">
     <route>
       <from uri="direct:start"/>
+      <setHeader headerName="bar">
+        <constant>Moes</constant>
+      </setHeader>
       <to uri="mock:a"/>
       <claimCheck operation="Push"/>
       <transform>
@@ -35,8 +38,12 @@
       <setHeader headerName="foo">
         <constant>456</constant>
       </setHeader>
+      <setHeader headerName="bar">
+        <constant>Jacks</constant>
+      </setHeader>
       <to uri="mock:b"/>
-      <claimCheck operation="Pop" include="body"/>
+      <!-- // skip the body and remove the bar header -->
+      <claimCheck operation="Pop" filter="-body,--header:bar"/>
       <to uri="mock:c"/>
     </route>
   </camelContext>

-- 
To stop receiving notification emails like this one, please contact
davsclaus@apache.org.

[camel] 01/03: CAMEL-8958: Claim Check EIP with push/pop. Work in progress.

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch 8958
in repository https://gitbox.apache.org/repos/asf/camel.git

commit c135f44eeaa2ba234ddc1c8294cb1077868d9ac7
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Feb 6 14:21:22 2018 +0100

    CAMEL-8958: Claim Check EIP with push/pop. Work in progress.
---
 .../apache/camel/model/ClaimCheckDefinition.java   | 105 ++++----
 .../apache/camel/model/ProcessorDefinition.java    |  25 +-
 .../processor/ClaimCheckAggregationStrategy.java   | 265 +++++++++++++++------
 .../camel/processor/ClaimCheckProcessor.java       |  22 +-
 .../ClaimCheckEipPushPopExcludeBodyTest.java       |   6 +-
 ...a => ClaimCheckEipPushPopRemoveHeaderTest.java} |  12 +-
 6 files changed, 274 insertions(+), 161 deletions(-)

diff --git a/camel-core/src/main/java/org/apache/camel/model/ClaimCheckDefinition.java b/camel-core/src/main/java/org/apache/camel/model/ClaimCheckDefinition.java
index 4dc1609..2b5dbce 100644
--- a/camel-core/src/main/java/org/apache/camel/model/ClaimCheckDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/ClaimCheckDefinition.java
@@ -46,9 +46,7 @@ public class ClaimCheckDefinition extends NoOutputDefinition<ClaimCheckDefinitio
     @XmlAttribute
     private String key;
     @XmlAttribute
-    private String include;
-    @XmlAttribute
-    private String exclude;
+    private String filter;
     @XmlAttribute(name = "strategyRef") @Metadata(label = "advanced")
     private String aggregationStrategyRef;
     @XmlAttribute(name = "strategyMethodName") @Metadata(label = "advanced")
@@ -80,17 +78,60 @@ public class ClaimCheckDefinition extends NoOutputDefinition<ClaimCheckDefinitio
         ClaimCheckProcessor claim = new ClaimCheckProcessor();
         claim.setOperation(operation.name());
         claim.setKey(getKey());
-        claim.setInclude(getInclude());
-        claim.setExclude(getExclude());
+        claim.setFilter(getFilter());
 
         AggregationStrategy strategy = createAggregationStrategy(routeContext);
         if (strategy != null) {
             claim.setAggregationStrategy(strategy);
         }
 
-        // only data or aggregation strategy can be configured not both
-        if ((getInclude() != null || getExclude() != null) && strategy != null) {
-            throw new IllegalArgumentException("Cannot use both include/exclude and custom aggregation strategy on ClaimCheck EIP");
+        // only filter or aggregation strategy can be configured not both
+        if (getFilter() != null && strategy != null) {
+            throw new IllegalArgumentException("Cannot use both filter and custom aggregation strategy on ClaimCheck EIP");
+        }
+
+        // validate filter, we cannot have both +/- at the same time
+        if (getFilter() != null) {
+            Iterable it = ObjectHelper.createIterable(filter, ",");
+            boolean includeBody = false;
+            boolean excludeBody = false;
+            for (Object o : it) {
+                String pattern = o.toString();
+                if ("body".equals(pattern) || "+body".equals(pattern)) {
+                    includeBody = true;
+                } else if ("-body".equals(pattern)) {
+                    excludeBody = true;
+                }
+            }
+            if (includeBody && excludeBody) {
+                throw new IllegalArgumentException("Cannot have both include and exclude body at the same time in the filter: " + filter);
+            }
+            boolean includeHeaders = false;
+            boolean excludeHeaders = false;
+            for (Object o : it) {
+                String pattern = o.toString();
+                if ("headers".equals(pattern) || "+headers".equals(pattern)) {
+                    includeHeaders = true;
+                } else if ("-headers".equals(pattern)) {
+                    excludeHeaders = true;
+                }
+            }
+            if (includeHeaders && excludeHeaders) {
+                throw new IllegalArgumentException("Cannot have both include and exclude headers at the same time in the filter: " + filter);
+            }
+            boolean includeHeader = false;
+            boolean excludeHeader = false;
+            for (Object o : it) {
+                String pattern = o.toString();
+                if (pattern.startsWith("header:") || pattern.startsWith("+header:")) {
+                    includeHeader = true;
+                } else if (pattern.startsWith("-header:")) {
+                    excludeHeader = true;
+                }
+            }
+            if (includeHeader && excludeHeader) {
+                throw new IllegalArgumentException("Cannot have both include and exclude header at the same time in the filter: " + filter);
+            }
         }
 
         return claim;
@@ -144,7 +185,7 @@ public class ClaimCheckDefinition extends NoOutputDefinition<ClaimCheckDefinitio
     }
 
     /**
-     * What data to include when merging data back from claim check repository.
+     * Specified a filter to control what data gets merging data back from the claim check repository.
      *
      * The following syntax is supported:
      * <ul>
@@ -155,30 +196,18 @@ public class ClaimCheckDefinition extends NoOutputDefinition<ClaimCheckDefinitio
      * </ul>
      * You can specify multiple rules separated by comma. For example to include the message body and all headers starting with foo
      * <tt>body,header:foo*</tt>.
-     * If the include rule is specified as empty or as wildcard then everything is included.
-     * If you have configured both include and exclude then exclude take precedence over include.
-     */
-    public ClaimCheckDefinition include(String include) {
-        setInclude(include);
-        return this;
-    }
-
-    /**
-     * What data to exclude when merging data back from claim check repository.
-     *
-     * The following syntax is supported:
+     * The syntax supports the following prefixes which can be used to specify include,exclude, or remove
      * <ul>
-     *     <li>body</li> - to aggregate the message body
-     *     <li>headers</li> - to aggregate all the message headers
-     *     <li>header:pattern</li> - to aggregate all the message headers that matches the pattern.
-     *     The pattern syntax is documented by: {@link EndpointHelper#matchPattern(String, String)}.
+     *     <li>+</li> - to include (which is the default mode)
+     *     <li>-</li> - to exclude (exclude takes precedence over include)
+     *     <li>--</li> - to remove (remove takes precedence)
      * </ul>
-     * You can specify multiple rules separated by comma. For example to exclude the message body and all headers starting with bar
-     * <tt>body,header:bar*</tt>.
-     * If you have configured both include and exclude then exclude take precedence over include.
+     * For example to exclude a header name foo, and remove all headers starting with bar
+     * <tt>-header:foo,--headers:bar*</tt>
+     * Note you cannot have both include and exclude <tt>header:pattern</tt> at the same time.
      */
-    public ClaimCheckDefinition exclude(String exclude) {
-        setExclude(exclude);
+    public ClaimCheckDefinition filter(String filter) {
+        setFilter(filter);
         return this;
     }
 
@@ -227,20 +256,12 @@ public class ClaimCheckDefinition extends NoOutputDefinition<ClaimCheckDefinitio
         this.operation = operation;
     }
 
-    public String getInclude() {
-        return include;
-    }
-
-    public void setInclude(String include) {
-        this.include = include;
-    }
-
-    public String getExclude() {
-        return exclude;
+    public String getFilter() {
+        return filter;
     }
 
-    public void setExclude(String exclude) {
-        this.exclude = exclude;
+    public void setFilter(String filter) {
+        this.filter = filter;
     }
 
     public String getAggregationStrategyRef() {
diff --git a/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinition.java b/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinition.java
index 39a0c6d..9544d93 100644
--- a/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinition.java
@@ -3478,7 +3478,7 @@ public abstract class ProcessorDefinition<Type extends ProcessorDefinition<Type>
      * @param key       the unique key to use for the get and set operations, can be <tt>null</tt> for push/pop operations
      */
     public Type claimCheck(ClaimCheckOperation operation, String key) {
-        return claimCheck(operation, key, null, null);
+        return claimCheck(operation, key, null);
     }
 
     /**
@@ -3488,30 +3488,13 @@ public abstract class ProcessorDefinition<Type extends ProcessorDefinition<Type>
      *
      * @param operation the claim check operation to use.
      * @param key       the unique key to use for the get and set operations, can be <tt>null</tt> for push/pop operations
-     * @param include   describes what data to include when merging data back when using get or pop operations.
+     * @param filter    describes what data to include/exclude when merging data back when using get or pop operations.
      */
-    public Type claimCheck(ClaimCheckOperation operation, String key, String include) {
-        return claimCheck(operation, key, include, null);
-    }
-
-    /**
-     * The <a href="http://camel.apache.org/claim-check.html">Claim Check EIP</a>
-     * allows you to replace message content with a claim check (a unique key),
-     * which can be used to retrieve the message content at a later time.
-     *
-     * @param operation the claim check operation to use.
-     * @param key       the unique key to use for the get and set operations, can be <tt>null</tt> for push/pop operations
-     * @param include   describes what data to include when merging data back when using get or pop operations.
-     *                  If you have configured both include and exclude then exclude take precedence over include.
-     * @param exclude   describes what data to exclude when merging data back when using get or pop operations.
-     *                  If you have configured both include and exclude then exclude take precedence over include.
-     */
-    public Type claimCheck(ClaimCheckOperation operation, String key, String include, String exclude) {
+    public Type claimCheck(ClaimCheckOperation operation, String key, String filter) {
         ClaimCheckDefinition answer = new ClaimCheckDefinition();
         answer.setOperation(operation);
         answer.setKey(key);
-        answer.setInclude(include);
-        answer.setExclude(exclude);
+        answer.setFilter(filter);
         addOutput(answer);
         return (Type) this;
     }
diff --git a/camel-core/src/main/java/org/apache/camel/processor/ClaimCheckAggregationStrategy.java b/camel-core/src/main/java/org/apache/camel/processor/ClaimCheckAggregationStrategy.java
index fb58346..b608ad2 100644
--- a/camel-core/src/main/java/org/apache/camel/processor/ClaimCheckAggregationStrategy.java
+++ b/camel-core/src/main/java/org/apache/camel/processor/ClaimCheckAggregationStrategy.java
@@ -16,7 +16,9 @@
  */
 package org.apache.camel.processor;
 
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.camel.Exchange;
 import org.apache.camel.processor.aggregate.AggregationStrategy;
@@ -44,26 +46,17 @@ import org.slf4j.LoggerFactory;
 public class ClaimCheckAggregationStrategy implements AggregationStrategy {
 
     private static final Logger LOG = LoggerFactory.getLogger(ClaimCheckAggregationStrategy.class);
-    private String include;
-    private String exclude;
+    private String filter;
 
     public ClaimCheckAggregationStrategy() {
     }
 
-    public String getInclude() {
-        return include;
+    public String getFilter() {
+        return filter;
     }
 
-    public void setInclude(String include) {
-        this.include = include;
-    }
-
-    public String getExclude() {
-        return exclude;
-    }
-
-    public void setExclude(String exclude) {
-        this.exclude = exclude;
+    public void setFilter(String filter) {
+        this.filter = filter;
     }
 
     @Override
@@ -72,91 +65,217 @@ public class ClaimCheckAggregationStrategy implements AggregationStrategy {
             return oldExchange;
         }
 
-        if (ObjectHelper.isEmpty(exclude) && (ObjectHelper.isEmpty(include) || "*".equals(include))) {
-            // grab everything if include is empty or wildcard (and exclude is not in use)
-            return newExchange;
+        if (ObjectHelper.isEmpty(filter) || "*".equals(filter)) {
+            // grab everything
+            oldExchange.getMessage().setBody(newExchange.getMessage().getBody());
+            LOG.trace("Including: body");
+            oldExchange.getMessage().getHeaders().putAll(newExchange.getMessage().getHeaders());
+            LOG.trace("Including: headers");
+            return oldExchange;
+        }
+
+        // body is by default often included
+        if (isBodyEnabled()) {
+            oldExchange.getMessage().setBody(newExchange.getMessage().getBody());
+            LOG.trace("Including: body");
+        }
+
+        // headers is by default often included
+        if (isHeadersEnabled()) {
+            oldExchange.getMessage().getHeaders().putAll(newExchange.getMessage().getHeaders());
+            LOG.trace("Including: headers");
+        }
+
+        // filter specific header if they are somehow enabled by the filter
+        if (hasHeaderPatterns()) {
+            boolean excludeOnly = isExcludeOnlyHeaderPatterns();
+            for (Map.Entry<String, Object> header : newExchange.getMessage().getHeaders().entrySet()) {
+                String key = header.getKey();
+                if (hasHeaderPattern(key)) {
+                    boolean include = isIncludedHeader(key);
+                    boolean exclude = isExcludedHeader(key);
+                    if (include) {
+                        LOG.trace("Including: header:{}", key);
+                        oldExchange.getMessage().getHeaders().put(key, header.getValue());
+                    } else if (exclude) {
+                        LOG.trace("Excluding: header:{}", key);
+                    } else {
+                        LOG.trace("Skipping: header:{}", key);
+                    }
+                } else if (excludeOnly) {
+                    LOG.trace("Including: header:{}", key);
+                    oldExchange.getMessage().getHeaders().put(key, header.getValue());
+                }
+            }
         }
 
-        // if we have include
-        if (ObjectHelper.isNotEmpty(include)) {
-            Iterable it = ObjectHelper.createIterable(include, ",");
+        // filter body and all headers
+        if (ObjectHelper.isNotEmpty(filter)) {
+            Iterable it = ObjectHelper.createIterable(filter, ",");
             for (Object k : it) {
                 String part = k.toString();
-                if ("body".equals(part) && !isExcluded("body")) {
+                if (("body".equals(part) || "+body".equals(part)) && !"-body".equals(part)) {
                     oldExchange.getMessage().setBody(newExchange.getMessage().getBody());
                     LOG.trace("Including: body");
-                } else if ("headers".equals(part) && !isExcluded("headers")) {
+                } else if (("headers".equals(part) || "+headers".equals(part)) && !"-headers".equals(part)) {
                     oldExchange.getMessage().getHeaders().putAll(newExchange.getMessage().getHeaders());
                     LOG.trace("Including: headers");
-                } else if (part.startsWith("header:")) {
-                    // pattern matching for headers, eg header:foo, header:foo*, header:(foo|bar)
-                    String after = StringHelper.after(part, "header:");
-                    Iterable i = ObjectHelper.createIterable(after, ",");
-                    for (Object o : i) {
-                        String pattern = o.toString();
-                        for (Map.Entry<String, Object> header : newExchange.getMessage().getHeaders().entrySet()) {
-                            String key = header.getKey();
-                            boolean matched = EndpointHelper.matchPattern(key, pattern);
-                            if (matched && !isExcluded(key)) {
-                                LOG.trace("Including: header:{}", key);
-                                oldExchange.getMessage().getHeaders().put(key, header.getValue());
-                            }
-                        }
-                    }
                 }
             }
-        } else if (ObjectHelper.isNotEmpty(exclude)) {
-            // grab body unless its excluded
-            if (!isExcluded("body")) {
-                oldExchange.getMessage().setBody(newExchange.getMessage().getBody());
-                LOG.trace("Including: body");
-            }
-
-            // if not all headers is excluded, then check each header one-by-one
-            if (!isExcluded("headers")) {
-                // check if we exclude a specific headers
-                Iterable it = ObjectHelper.createIterable(exclude, ",");
-                for (Object k : it) {
-                    String part = k.toString();
-                    if (part.startsWith("header:")) {
-                        // pattern matching for headers, eg header:foo, header:foo*, header:(foo|bar)
-                        String after = StringHelper.after(part, "header:");
-                        Iterable i = ObjectHelper.createIterable(after, ",");
-                        for (Object o : i) {
-                            String pattern = o.toString();
-                            for (Map.Entry<String, Object> header : newExchange.getMessage().getHeaders().entrySet()) {
-                                String key = header.getKey();
-                                boolean excluded = EndpointHelper.matchPattern(key, pattern);
-                                if (!excluded) {
-                                    LOG.trace("Including: header:{}", key);
-                                    oldExchange.getMessage().getHeaders().put(key, header.getValue());
-                                } else {
-                                    LOG.trace("Excluding: header:{}", key);
-                                }
-                            }
+        }
+
+        // filter with remove (--) take precedence at the end
+        Iterable it = ObjectHelper.createIterable(filter, ",");
+        for (Object k : it) {
+            String part = k.toString();
+            if ("--body".equals(part)) {
+                oldExchange.getMessage().setBody(null);
+            } else if ("--headers".equals(part)) {
+                oldExchange.getMessage().getHeaders().clear();
+            } else if (part.startsWith("--header:")) {
+                // pattern matching for headers, eg header:foo, header:foo*, header:(foo|bar)
+                String after = StringHelper.after(part, "--header:");
+                Iterable i = ObjectHelper.createIterable(after, ",");
+                Set<String> toRemoveKeys = new HashSet<>();
+                for (Object o : i) {
+                    String pattern = o.toString();
+                    for (Map.Entry<String, Object> header : oldExchange.getMessage().getHeaders().entrySet()) {
+                        String key = header.getKey();
+                        boolean matched = EndpointHelper.matchPattern(key, pattern);
+                        if (matched) {
+                            toRemoveKeys.add(key);
                         }
                     }
                 }
+                for (String key : toRemoveKeys) {
+                    LOG.trace("Removing: header:{}", key);
+                    oldExchange.getMessage().removeHeader(key);
+                }
             }
         }
 
         return oldExchange;
     }
 
-    private boolean isExcluded(String key) {
-        if (ObjectHelper.isEmpty(exclude)) {
-            return false;
+    private boolean hasHeaderPatterns() {
+        String[] parts = filter.split(",");
+        for (String pattern : parts) {
+            if (pattern.startsWith("--")) {
+                continue;
+            }
+            if (pattern.startsWith("header:") || pattern.startsWith("+header:") || pattern.startsWith("-header:")) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isExcludeOnlyHeaderPatterns() {
+        String[] parts = filter.split(",");
+        for (String pattern : parts) {
+            if (pattern.startsWith("--")) {
+                continue;
+            }
+            if (pattern.startsWith("header:") || pattern.startsWith("+header:")) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean hasHeaderPattern(String key) {
+        String[] parts = filter.split(",");
+        for (String pattern : parts) {
+            if (pattern.startsWith("--")) {
+                continue;
+            }
+            String header = null;
+            if (pattern.startsWith("header:") || pattern.startsWith("+header:")) {
+                header = StringHelper.after(pattern, "header:");
+            } else if (pattern.startsWith("-header:")) {
+                header = StringHelper.after(pattern, "-header:");
+            }
+            if (header != null && EndpointHelper.matchPattern(key, header)) {
+                return true;
+            }
         }
-        String[] excludes = exclude.split(",");
-        for (String pattern : excludes) {
-            if (pattern.startsWith("header:")) {
+        return false;
+    }
+
+    private boolean isIncludedHeader(String key) {
+        String[] parts = filter.split(",");
+        for (String pattern : parts) {
+            if (pattern.startsWith("--")) {
+                continue;
+            }
+            if (pattern.startsWith("header:") || pattern.startsWith("+header:")) {
                 pattern = StringHelper.after(pattern, "header:");
             }
             if (EndpointHelper.matchPattern(key, pattern)) {
-                LOG.trace("Excluding: {}", key);
                 return true;
             }
         }
         return false;
     }
+
+    private boolean isExcludedHeader(String key) {
+        String[] parts = filter.split(",");
+        for (String pattern : parts) {
+            if (pattern.startsWith("--")) {
+                continue;
+            }
+            if (pattern.startsWith("-header:")) {
+                pattern = StringHelper.after(pattern, "-header:");
+            }
+            if (EndpointHelper.matchPattern(key, pattern)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean isBodyEnabled() {
+        // body is always enabled unless excluded
+        String[] parts = filter.split(",");
+
+        boolean onlyExclude = true;
+        for (String pattern : parts) {
+            if (pattern.startsWith("--")) {
+                continue;
+            }
+            if ("body".equals(pattern) || "+body".equals(pattern)) {
+                return true;
+            } else if ("-body".equals(pattern)) {
+                return false;
+            }
+            onlyExclude &= pattern.startsWith("-");
+        }
+        // body is enabled if we only have exclude patterns
+        return onlyExclude;
+    }
+
+    private boolean isHeadersEnabled() {
+        // headers may be enabled unless excluded
+        String[] parts = filter.split(",");
+
+        boolean onlyExclude = true;
+        for (String pattern : parts) {
+            if (pattern.startsWith("--")) {
+                continue;
+            }
+            // if there is individual header filters then we cannot rely on this
+            if (pattern.startsWith("header:") || pattern.startsWith("+header:") || pattern.startsWith("-header:")) {
+                return false;
+            }
+            if ("headers".equals(pattern) || "+headers".equals(pattern)) {
+                return true;
+            } else if ("-headers".equals(pattern)) {
+                return false;
+            }
+            onlyExclude &= pattern.startsWith("-");
+        }
+        // headers is enabled if we only have exclude patterns
+        return onlyExclude;
+    }
+
 }
diff --git a/camel-core/src/main/java/org/apache/camel/processor/ClaimCheckProcessor.java b/camel-core/src/main/java/org/apache/camel/processor/ClaimCheckProcessor.java
index 2421878..cedf95f 100644
--- a/camel-core/src/main/java/org/apache/camel/processor/ClaimCheckProcessor.java
+++ b/camel-core/src/main/java/org/apache/camel/processor/ClaimCheckProcessor.java
@@ -49,8 +49,7 @@ public class ClaimCheckProcessor extends ServiceSupport implements AsyncProcesso
     private String operation;
     private AggregationStrategy aggregationStrategy;
     private String key;
-    private String include;
-    private String exclude;
+    private String filter;
 
     @Override
     public CamelContext getCamelContext() {
@@ -96,20 +95,12 @@ public class ClaimCheckProcessor extends ServiceSupport implements AsyncProcesso
         this.key = key;
     }
 
-    public String getInclude() {
-        return include;
+    public String getFilter() {
+        return filter;
     }
 
-    public void setInclude(String include) {
-        this.include = include;
-    }
-
-    public String getExclude() {
-        return exclude;
-    }
-
-    public void setExclude(String exclude) {
-        this.exclude = exclude;
+    public void setFilter(String filter) {
+        this.filter = filter;
     }
 
     public void process(Exchange exchange) throws Exception {
@@ -206,8 +197,7 @@ public class ClaimCheckProcessor extends ServiceSupport implements AsyncProcesso
 
     protected AggregationStrategy createAggregationStrategy() {
         ClaimCheckAggregationStrategy answer = new ClaimCheckAggregationStrategy();
-        answer.setInclude(include);
-        answer.setExclude(exclude);
+        answer.setFilter(filter);
         return answer;
     }
 }
diff --git a/camel-core/src/test/java/org/apache/camel/processor/ClaimCheckEipPushPopExcludeBodyTest.java b/camel-core/src/test/java/org/apache/camel/processor/ClaimCheckEipPushPopExcludeBodyTest.java
index 6ddbb29..4e0e0fb 100644
--- a/camel-core/src/test/java/org/apache/camel/processor/ClaimCheckEipPushPopExcludeBodyTest.java
+++ b/camel-core/src/test/java/org/apache/camel/processor/ClaimCheckEipPushPopExcludeBodyTest.java
@@ -29,7 +29,7 @@ public class ClaimCheckEipPushPopExcludeBodyTest extends ContextTestSupport {
         getMockEndpoint("mock:b").expectedBodiesReceived("Bye World");
         getMockEndpoint("mock:b").expectedHeaderReceived("foo", 456);
         getMockEndpoint("mock:b").expectedHeaderReceived("bar", "Jacks");
-        getMockEndpoint("mock:c").expectedBodiesReceived("Hello World");
+        getMockEndpoint("mock:c").expectedBodiesReceived("Bye World");
         getMockEndpoint("mock:c").expectedHeaderReceived("foo", 123);
         getMockEndpoint("mock:c").expectedHeaderReceived("bar", "Jacks");
 
@@ -51,8 +51,8 @@ public class ClaimCheckEipPushPopExcludeBodyTest extends ContextTestSupport {
                     .setHeader("foo", constant(456))
                     .setHeader("bar", constant("Jacks"))
                     .to("mock:b")
-                    // skip the foo header
-                    .claimCheck(ClaimCheckOperation.Pop, null, null, "header:bar")
+                    // skip the body and bar header
+                    .claimCheck(ClaimCheckOperation.Pop, null, "-body,-header:bar")
                     .to("mock:c");
             }
         };
diff --git a/camel-core/src/test/java/org/apache/camel/processor/ClaimCheckEipPushPopExcludeBodyTest.java b/camel-core/src/test/java/org/apache/camel/processor/ClaimCheckEipPushPopRemoveHeaderTest.java
similarity index 83%
copy from camel-core/src/test/java/org/apache/camel/processor/ClaimCheckEipPushPopExcludeBodyTest.java
copy to camel-core/src/test/java/org/apache/camel/processor/ClaimCheckEipPushPopRemoveHeaderTest.java
index 6ddbb29..c164d64 100644
--- a/camel-core/src/test/java/org/apache/camel/processor/ClaimCheckEipPushPopExcludeBodyTest.java
+++ b/camel-core/src/test/java/org/apache/camel/processor/ClaimCheckEipPushPopRemoveHeaderTest.java
@@ -20,18 +20,18 @@ import org.apache.camel.ContextTestSupport;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.model.ClaimCheckOperation;
 
-public class ClaimCheckEipPushPopExcludeBodyTest extends ContextTestSupport {
+public class ClaimCheckEipPushPopRemoveHeaderTest extends ContextTestSupport {
 
-    public void testPushPopBodyExclude() throws Exception {
+    public void testPushPopBodyRemoveHeader() throws Exception {
         getMockEndpoint("mock:a").expectedBodiesReceived("Hello World");
         getMockEndpoint("mock:a").expectedHeaderReceived("foo", 123);
         getMockEndpoint("mock:a").expectedHeaderReceived("bar", "Moes");
         getMockEndpoint("mock:b").expectedBodiesReceived("Bye World");
         getMockEndpoint("mock:b").expectedHeaderReceived("foo", 456);
         getMockEndpoint("mock:b").expectedHeaderReceived("bar", "Jacks");
-        getMockEndpoint("mock:c").expectedBodiesReceived("Hello World");
+        getMockEndpoint("mock:c").expectedBodiesReceived("Bye World");
         getMockEndpoint("mock:c").expectedHeaderReceived("foo", 123);
-        getMockEndpoint("mock:c").expectedHeaderReceived("bar", "Jacks");
+        getMockEndpoint("mock:c").message(0).header("bar").isNull();
 
         template.sendBodyAndHeader("direct:start", "Hello World", "foo", 123);
 
@@ -51,8 +51,8 @@ public class ClaimCheckEipPushPopExcludeBodyTest extends ContextTestSupport {
                     .setHeader("foo", constant(456))
                     .setHeader("bar", constant("Jacks"))
                     .to("mock:b")
-                    // skip the foo header
-                    .claimCheck(ClaimCheckOperation.Pop, null, null, "header:bar")
+                    // skip the body and remove the bar header
+                    .claimCheck(ClaimCheckOperation.Pop, null, "-body,--header:bar")
                     .to("mock:c");
             }
         };

-- 
To stop receiving notification emails like this one, please contact
davsclaus@apache.org.