CAMEL-8488: Java DSL - Improved CBR to detect if endChoice vs end was invalid used
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/5c286b32 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/5c286b32 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/5c286b32 Branch: refs/heads/camel-2.15.x Commit: 5c286b322fc910ebf4a53f9f7a2b8f5b7c505d3a Parents: c75ca16 Author: Claus Ibsen <davscl...@apache.org> Authored: Sun Mar 15 09:50:51 2015 +0100 Committer: Claus Ibsen <davscl...@apache.org> Committed: Sun Mar 15 10:52:11 2015 +0100 ---------------------------------------------------------------------- .../apache/camel/model/ChoiceDefinition.java | 30 ++++++ .../issues/ChoiceEndOrEndChoiceIssueTest.java | 105 +++++++++++++++++++ 2 files changed, 135 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/5c286b32/camel-core/src/main/java/org/apache/camel/model/ChoiceDefinition.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/model/ChoiceDefinition.java b/camel-core/src/main/java/org/apache/camel/model/ChoiceDefinition.java index b2160de..a27502b 100644 --- a/camel-core/src/main/java/org/apache/camel/model/ChoiceDefinition.java +++ b/camel-core/src/main/java/org/apache/camel/model/ChoiceDefinition.java @@ -48,6 +48,8 @@ public class ChoiceDefinition extends ProcessorDefinition<ChoiceDefinition> { @XmlElement private OtherwiseDefinition otherwise; + private transient boolean onlyWhenOrOtherwise = true; + public ChoiceDefinition() { } @@ -138,6 +140,33 @@ public class ChoiceDefinition extends ProcessorDefinition<ChoiceDefinition> { return new ChoiceProcessor(filters, otherwiseProcessor); } + @Override + public void addOutput(ProcessorDefinition<?> output) { + if (onlyWhenOrOtherwise) { + if (output instanceof WhenDefinition || output instanceof OtherwiseDefinition) { + // okay we are adding a when or otherwise so allow any kind of output after this again + onlyWhenOrOtherwise = false; + } else { + throw new IllegalArgumentException("A new choice clause should start with a when() or otherwise(). If you intend to end the entire choice and are using endChoice() then use end() instead."); + } + } + super.addOutput(output); + } + + @Override + public ProcessorDefinition<?> end() { + // we end a block so only when or otherwise is supported + onlyWhenOrOtherwise = true; + return super.end(); + } + + @Override + public ChoiceDefinition endChoice() { + // we end a block so only when or otherwise is supported + onlyWhenOrOtherwise = true; + return super.endChoice(); + } + // Fluent API // ------------------------------------------------------------------------- @@ -164,6 +193,7 @@ public class ChoiceDefinition extends ProcessorDefinition<ChoiceDefinition> { } private void addClause(ProcessorDefinition<?> when) { + onlyWhenOrOtherwise = true; popBlock(); addOutput(when); pushBlock(when); http://git-wip-us.apache.org/repos/asf/camel/blob/5c286b32/camel-core/src/test/java/org/apache/camel/issues/ChoiceEndOrEndChoiceIssueTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/issues/ChoiceEndOrEndChoiceIssueTest.java b/camel-core/src/test/java/org/apache/camel/issues/ChoiceEndOrEndChoiceIssueTest.java new file mode 100644 index 0000000..5566a8e --- /dev/null +++ b/camel-core/src/test/java/org/apache/camel/issues/ChoiceEndOrEndChoiceIssueTest.java @@ -0,0 +1,105 @@ +/** + * 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.issues; + +import org.apache.camel.ContextTestSupport; +import org.apache.camel.builder.RouteBuilder; + +public class ChoiceEndOrEndChoiceIssueTest extends ContextTestSupport { + + @Override + public boolean isUseRouteBuilder() { + return false; + } + + public void testEndChoiceInvalid() throws Exception { + try { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .choice() + .when(header("number").isEqualTo("one")).to("mock:one") + .when(header("number").isEqualTo("two")).to("mock:two") + .when(header("number").isEqualTo("three")).to("mock:three") + .endChoice() + .to("mock:finally"); + } + }); + context.start(); + fail("Should have thrown exception"); + } catch (IllegalArgumentException e) { + assertEquals("A new choice clause should start with a when() or otherwise()." + + " If you intend to end the entire choice and are using endChoice() then use end() instead.", e.getMessage()); + } + } + + public void testEndChoiceValid() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .choice() + .when(header("number").isEqualTo("one")).to("mock:one") + .when(header("number").isEqualTo("two")).to("mock:two") + .when(header("number").isEqualTo("three")).to("mock:three") + .end() + .to("mock:finally"); + } + }); + context.start(); + + getMockEndpoint("mock:one").expectedHeaderReceived("number", "one"); + getMockEndpoint("mock:two").expectedHeaderReceived("number", "two"); + getMockEndpoint("mock:three").expectedHeaderReceived("number", "three"); + getMockEndpoint("mock:finally").expectedBodiesReceived("1", "2", "3"); + + template.sendBodyAndHeader("direct:start", "1", "number", "one"); + template.sendBodyAndHeader("direct:start", "2", "number", "two"); + template.sendBodyAndHeader("direct:start", "3", "number", "three"); + + assertMockEndpointsSatisfied(); + } + + public void testEndChoiceEndValid() throws Exception { + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .choice() + .when(header("number").isEqualTo("one")).to("mock:one") + .when(header("number").isEqualTo("two")).to("mock:two") + .when(header("number").isEqualTo("three")).to("mock:three") + .endChoice().end() + .to("mock:finally"); + } + }); + context.start(); + + getMockEndpoint("mock:one").expectedHeaderReceived("number", "one"); + getMockEndpoint("mock:two").expectedHeaderReceived("number", "two"); + getMockEndpoint("mock:three").expectedHeaderReceived("number", "three"); + getMockEndpoint("mock:finally").expectedBodiesReceived("1", "2", "3"); + + template.sendBodyAndHeader("direct:start", "1", "number", "one"); + template.sendBodyAndHeader("direct:start", "2", "number", "two"); + template.sendBodyAndHeader("direct:start", "3", "number", "three"); + + assertMockEndpointsSatisfied(); + } + +}