Author: davsclaus
Date: Thu Jan  5 09:00:27 2012
New Revision: 1227529

URL: http://svn.apache.org/viewvc?rev=1227529&view=rev
Log:
CAMEL-4809: Fixed interceptSendToEndpoint with when predicate and skip option 
enabled, should only skip sending if the predicate was true. Thanks to Raul for 
part of this work.

Added:
    
camel/trunk/camel-core/src/main/java/org/apache/camel/model/WhenSkipSendToEndpointDefinition.java
    
camel/trunk/camel-core/src/test/java/org/apache/camel/processor/intercept/InterceptSendToEndpointConditionalSkipTest.java
Modified:
    camel/trunk/camel-core/src/main/java/org/apache/camel/Exchange.java
    
camel/trunk/camel-core/src/main/java/org/apache/camel/impl/InterceptSendToEndpoint.java
    
camel/trunk/camel-core/src/main/java/org/apache/camel/model/ExpressionNode.java
    
camel/trunk/camel-core/src/main/java/org/apache/camel/model/FilterDefinition.java
    
camel/trunk/camel-core/src/main/java/org/apache/camel/model/InterceptSendToEndpointDefinition.java

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/Exchange.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/Exchange.java?rev=1227529&r1=1227528&r2=1227529&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/Exchange.java 
(original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/Exchange.java Thu Jan 
 5 09:00:27 2012
@@ -136,6 +136,7 @@ public interface Exchange {
     String HTTP_SERVLET_RESPONSE   = "CamelHttpServletResponse";
 
     String INTERCEPTED_ENDPOINT = "CamelInterceptedEndpoint";
+    String INTERCEPT_SEND_TO_ENDPOINT_WHEN_MATCHED = 
"CamelInterceptSendToEndpointWhenMatched";
 
     String LANGUAGE_SCRIPT          = "CamelLanguageScript";
     String LOG_DEBUG_BODY_MAX_CHARS = "CamelLogDebugBodyMaxChars";

Modified: 
camel/trunk/camel-core/src/main/java/org/apache/camel/impl/InterceptSendToEndpoint.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/InterceptSendToEndpoint.java?rev=1227529&r1=1227528&r2=1227529&view=diff
==============================================================================
--- 
camel/trunk/camel-core/src/main/java/org/apache/camel/impl/InterceptSendToEndpoint.java
 (original)
+++ 
camel/trunk/camel-core/src/main/java/org/apache/camel/impl/InterceptSendToEndpoint.java
 Thu Jan  5 09:00:27 2012
@@ -73,6 +73,7 @@ public class InterceptSendToEndpoint imp
     public EndpointConfiguration getEndpointConfiguration() {
         return delegate.getEndpointConfiguration();
     }
+
     public String getEndpointKey() {
         return delegate.getEndpointKey();
     }
@@ -133,7 +134,16 @@ public class InterceptSendToEndpoint imp
                     return;
                 }
 
-                if (!skip) {
+                // determine if we should skip or not
+                boolean shouldSkip = skip;
+
+                // if then interceptor had a when predicate, then we should 
only skip if it matched
+                Boolean whenMatches = (Boolean) 
exchange.removeProperty(Exchange.INTERCEPT_SEND_TO_ENDPOINT_WHEN_MATCHED);
+                if (whenMatches != null) {
+                    shouldSkip = skip && whenMatches;
+                }
+
+                if (!shouldSkip) {
                     if (exchange.hasOut()) {
                         // replace OUT with IN as detour changed something
                         exchange.setIn(exchange.getOut());

Modified: 
camel/trunk/camel-core/src/main/java/org/apache/camel/model/ExpressionNode.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/model/ExpressionNode.java?rev=1227529&r1=1227528&r2=1227529&view=diff
==============================================================================
--- 
camel/trunk/camel-core/src/main/java/org/apache/camel/model/ExpressionNode.java 
(original)
+++ 
camel/trunk/camel-core/src/main/java/org/apache/camel/model/ExpressionNode.java 
Thu Jan  5 09:00:27 2012
@@ -97,9 +97,26 @@ public class ExpressionNode extends Proc
         return getExpression().getLabel();
     }
 
+    /**
+     * Creates the {@link FilterProcessor} from the expression node.
+     *
+     * @param routeContext  the route context
+     * @return the created {@link FilterProcessor}
+     * @throws Exception is thrown if error creating the processor
+     */
     protected FilterProcessor createFilterProcessor(RouteContext routeContext) 
throws Exception {
         Processor childProcessor = this.createChildProcessor(routeContext, 
false);
-        return new 
FilterProcessor(getExpression().createPredicate(routeContext), childProcessor);
+        return new FilterProcessor(createPredicate(routeContext), 
childProcessor);
+    }
+
+    /**
+     * Creates the {@link Predicate} from the expression node.
+     *
+     * @param routeContext  the route context
+     * @return the created predicate
+     */
+    protected Predicate createPredicate(RouteContext routeContext) {
+        return getExpression().createPredicate(routeContext);
     }
 
     @Override

Modified: 
camel/trunk/camel-core/src/main/java/org/apache/camel/model/FilterDefinition.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/model/FilterDefinition.java?rev=1227529&r1=1227528&r2=1227529&view=diff
==============================================================================
--- 
camel/trunk/camel-core/src/main/java/org/apache/camel/model/FilterDefinition.java
 (original)
+++ 
camel/trunk/camel-core/src/main/java/org/apache/camel/model/FilterDefinition.java
 Thu Jan  5 09:00:27 2012
@@ -61,7 +61,6 @@ public class FilterDefinition extends Ex
         return "filter";
     }
 
-
     @Override
     public FilterProcessor createProcessor(RouteContext routeContext) throws 
Exception {
         return createFilterProcessor(routeContext);
@@ -71,7 +70,7 @@ public class FilterDefinition extends Ex
     protected FilterProcessor createFilterProcessor(RouteContext routeContext) 
throws Exception {
         // filter EIP should have child outputs
         Processor childProcessor = this.createChildProcessor(routeContext, 
true);
-        return new 
FilterProcessor(getExpression().createPredicate(routeContext), childProcessor);
+        return new FilterProcessor(createPredicate(routeContext), 
childProcessor);
     }
 
 }

Modified: 
camel/trunk/camel-core/src/main/java/org/apache/camel/model/InterceptSendToEndpointDefinition.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/model/InterceptSendToEndpointDefinition.java?rev=1227529&r1=1227528&r2=1227529&view=diff
==============================================================================
--- 
camel/trunk/camel-core/src/main/java/org/apache/camel/model/InterceptSendToEndpointDefinition.java
 (original)
+++ 
camel/trunk/camel-core/src/main/java/org/apache/camel/model/InterceptSendToEndpointDefinition.java
 Thu Jan  5 09:00:27 2012
@@ -87,14 +87,13 @@ public class InterceptSendToEndpointDefi
         // register endpoint callback so we can proxy the endpoint
         routeContext.getCamelContext().addRegisterEndpointCallback(new 
EndpointStrategy() {
             public Endpoint registerEndpoint(String uri, Endpoint endpoint) {
-                
                 if (endpoint instanceof InterceptSendToEndpoint) {
                     // endpoint already decorated
                     return endpoint;
                 } else if (getUri() == null || 
EndpointHelper.matchEndpoint(uri, getUri())) {
                     // only proxy if the uri is matched decorate endpoint with 
our proxy
                     // should be false by default
-                    boolean skip = getSkipSendToOriginalEndpoint() != null ? 
getSkipSendToOriginalEndpoint() : false;
+                    boolean skip = isSkipSendToOriginalEndpoint();
                     InterceptSendToEndpoint proxy = new 
InterceptSendToEndpoint(endpoint, skip);
                     proxy.setDetour(detour);
                     return proxy;
@@ -153,19 +152,30 @@ public class InterceptSendToEndpointDefi
             return;
         }
 
+        // if there is a when definition at first, then its a predicate for 
this interceptor
         ProcessorDefinition first = getOutputs().get(0);
-        if (first instanceof WhenDefinition) {
+        if (first instanceof WhenDefinition && !(first instanceof 
WhenSkipSendToEndpointDefinition)) {
             WhenDefinition when = (WhenDefinition) first;
+
+            // create a copy of when to use as replacement
+            WhenSkipSendToEndpointDefinition newWhen = new 
WhenSkipSendToEndpointDefinition();
+            newWhen.setExpression(when.getExpression());
+            newWhen.setId(when.getId());
+            newWhen.setInheritErrorHandler(when.isInheritErrorHandler());
+            newWhen.setParent(when.getParent());
+            newWhen.setOtherAttributes(when.getOtherAttributes());
+            newWhen.setNodeFactory(when.getNodeFactory());
+            newWhen.setDescription(when.getDescription());
+
             // move this outputs to the when, expect the first one
             // as the first one is the interceptor itself
             for (int i = 1; i < outputs.size(); i++) {
                 ProcessorDefinition out = outputs.get(i);
-                when.addOutput(out);
+                newWhen.addOutput(out);
             }
             // remove the moved from the original output, by just keeping the 
first one
-            ProcessorDefinition keep = outputs.get(0);
             clearOutput();
-            outputs.add(keep);
+            outputs.add(newWhen);
         }
     }
 
@@ -176,6 +186,10 @@ public class InterceptSendToEndpointDefi
     public void setSkipSendToOriginalEndpoint(Boolean 
skipSendToOriginalEndpoint) {
         this.skipSendToOriginalEndpoint = skipSendToOriginalEndpoint;
     }
+    
+    public boolean isSkipSendToOriginalEndpoint() {
+        return skipSendToOriginalEndpoint != null && 
skipSendToOriginalEndpoint;
+    }
 
     public String getUri() {
         return uri;

Added: 
camel/trunk/camel-core/src/main/java/org/apache/camel/model/WhenSkipSendToEndpointDefinition.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/model/WhenSkipSendToEndpointDefinition.java?rev=1227529&view=auto
==============================================================================
--- 
camel/trunk/camel-core/src/main/java/org/apache/camel/model/WhenSkipSendToEndpointDefinition.java
 (added)
+++ 
camel/trunk/camel-core/src/main/java/org/apache/camel/model/WhenSkipSendToEndpointDefinition.java
 Thu Jan  5 09:00:27 2012
@@ -0,0 +1,48 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.model;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Predicate;
+import org.apache.camel.spi.RouteContext;
+
+/**
+ *
+ */
+public class WhenSkipSendToEndpointDefinition extends WhenDefinition {
+
+    @Override
+    protected Predicate createPredicate(RouteContext routeContext) {
+        // we need to keep track whether the when matches or not, so delegate
+        // the predicate and add the matches result as a property on the 
exchange
+        final Predicate delegate = super.createPredicate(routeContext);
+        return new Predicate() {
+            @Override
+            public boolean matches(Exchange exchange) {
+                boolean matches = delegate.matches(exchange);
+                
exchange.setProperty(Exchange.INTERCEPT_SEND_TO_ENDPOINT_WHEN_MATCHED, matches);
+                return matches;
+            }
+
+            @Override
+            public String toString() {
+                return delegate.toString();
+            }
+        };
+    }
+
+}

Added: 
camel/trunk/camel-core/src/test/java/org/apache/camel/processor/intercept/InterceptSendToEndpointConditionalSkipTest.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/intercept/InterceptSendToEndpointConditionalSkipTest.java?rev=1227529&view=auto
==============================================================================
--- 
camel/trunk/camel-core/src/test/java/org/apache/camel/processor/intercept/InterceptSendToEndpointConditionalSkipTest.java
 (added)
+++ 
camel/trunk/camel-core/src/test/java/org/apache/camel/processor/intercept/InterceptSendToEndpointConditionalSkipTest.java
 Thu Jan  5 09:00:27 2012
@@ -0,0 +1,129 @@
+/**
+ * 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.intercept;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.builder.RouteBuilder;
+
+/**
+ * Unit tests on the conditional skip support on InterceptSendToEndpoint.
+ * 
+ * @version
+ */
+public class InterceptSendToEndpointConditionalSkipTest extends 
ContextTestSupport {
+
+    /**
+     * Verify that the endpoint is only skipped if the adjacent 'when' 
condition is satisfied
+     */
+    public void testInterceptSendToEndpointSkipConditionSatisfied() throws 
Exception {
+        getMockEndpoint("mock:a").expectedMessageCount(1);
+        getMockEndpoint("mock:skippable").expectedMessageCount(0);
+        getMockEndpoint("mock:detour").expectedMessageCount(1);
+        getMockEndpoint("mock:c").expectedMessageCount(1);
+
+        template.sendBody("direct:start", "skip");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    /**
+     * Verify that the endpoint is not skipped if the adjacent 'when' 
condition evaluates to false
+     */
+    public void testInterceptSendToEndpointSkipConditionNotSatisfied() throws 
Exception {
+        getMockEndpoint("mock:a").expectedMessageCount(1);
+        getMockEndpoint("mock:skippable").expectedMessageCount(1);
+        getMockEndpoint("mock:detour").expectedMessageCount(0);
+        getMockEndpoint("mock:c").expectedMessageCount(1);
+
+        template.sendBody("direct:start", "Hello World");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    /**
+     * Verify that the conditional skip support is only activated when using 
interceptSendToEndpoint().when() and not
+     * interceptSendToEndpoint().choice()..., as the choice keyword is not 
directly associated with the interception behaviour and it belongs to the
+     * interception body (initiating a new routing block)
+     */
+    public void testInterceptSendToEndpointSkipConditionNoEffectChoice() 
throws Exception {
+        getMockEndpoint("mock:a").expectedMessageCount(2);
+        getMockEndpoint("mock:skippableNoEffect").expectedMessageCount(0);
+        getMockEndpoint("mock:c").expectedMessageCount(2);
+
+        getMockEndpoint("mock:noSkipWhen").expectedMessageCount(1);
+        getMockEndpoint("mock:noSkipOW").expectedMessageCount(1);
+
+        template.sendBody("direct:startNoEffect", "skipNoEffectWhen");
+        template.sendBody("direct:startNoEffect", "Hello Camel");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    /**
+     * Test that when multiple conditions are chained together in Java DSL, 
only the first one will determine whether the endpoint is skipped or not
+     */
+    public void testInterceptSendToEndpointSkipMultipleConditions() throws 
Exception {
+        getMockEndpoint("mock:a").expectedMessageCount(1);
+        
getMockEndpoint("mock:skippableMultipleConditions").expectedMessageCount(0);
+        getMockEndpoint("mock:detour").expectedMessageCount(1);
+        getMockEndpoint("mock:c").expectedMessageCount(1);
+
+        template.sendBody("direct:startMultipleConditions", "skip");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                // only skip if the body equals 'skip'
+                
interceptSendToEndpoint("mock:skippable").skipSendToOriginalEndpoint()
+                        .when(body().isEqualTo("skip")).to("mock:detour");
+
+                // always skip with a normal with a normal choice inside 
instructing where to route instead
+                
interceptSendToEndpoint("mock:skippableNoEffect").skipSendToOriginalEndpoint()
+                        .choice()
+                        
.when(body().isEqualTo("skipNoEffectWhen")).to("mock:noSkipWhen")
+                        .otherwise().to("mock:noSkipOW");
+
+                // in this case, the original endpoint will be skipped but no 
message will be sent to mock:detour
+                
interceptSendToEndpoint("mock:skippableMultipleConditions").skipSendToOriginalEndpoint()
+                        .when(body().isEqualTo("skip"))
+                        .when(body().isNotEqualTo("skip"))
+                            .to("mock:detour");
+
+                from("direct:start")
+                        .to("mock:a")
+                        .to("mock:skippable")
+                        .to("mock:c");
+
+                from("direct:startNoEffect")
+                        .to("mock:a")
+                        .to("mock:skippableNoEffect")
+                        .to("mock:c");
+
+                from("direct:startMultipleConditions")
+                        .to("mock:a")
+                        .to("mock:skippableMultipleConditions")
+                        .to("mock:c");
+            }
+        };
+    }
+
+}


Reply via email to