Repository: camel Updated Branches: refs/heads/camel-2.12.x ac3a3281f -> 2460888dc
CAMEL-7560: Fixed advice with when using transacted in the XML routes. Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/70f15415 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/70f15415 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/70f15415 Branch: refs/heads/camel-2.12.x Commit: 70f15415c732900f15dd2676e24131b69abf9627 Parents: ac3a328 Author: Claus Ibsen <davscl...@apache.org> Authored: Mon Jun 30 21:12:56 2014 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Wed Jul 2 09:35:42 2014 +0200 ---------------------------------------------------------------------- .../apache/camel/builder/AdviceWithTasks.java | 65 ++++++++++------ .../camel/model/ProcessorDefinitionHelper.java | 10 +++ .../camel/issues/AdviceWithPolicyTest.java | 78 ++++++++++++++++++++ .../issues/AdviceWithTransactionIssueTest.java | 76 +++++++++++++++++++ .../issues/AdviceWithTransactionIssueTest.xml | 35 +++++++++ .../jms/AdviceWithTransactionIssueTest.java | 76 +++++++++++++++++++ .../jms/AdviceWithTransactionIssueTest.xml | 58 +++++++++++++++ 7 files changed, 377 insertions(+), 21 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/70f15415/camel-core/src/main/java/org/apache/camel/builder/AdviceWithTasks.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/builder/AdviceWithTasks.java b/camel-core/src/main/java/org/apache/camel/builder/AdviceWithTasks.java index b827f8f..69f5a0a 100644 --- a/camel-core/src/main/java/org/apache/camel/builder/AdviceWithTasks.java +++ b/camel-core/src/main/java/org/apache/camel/builder/AdviceWithTasks.java @@ -143,13 +143,13 @@ public final class AdviceWithTasks { while (it.hasNext()) { ProcessorDefinition<?> output = it.next(); if (matchBy.match(output)) { - ProcessorDefinition<?> parent = output.getParent(); - if (parent != null) { - int index = parent.getOutputs().indexOf(output); + List<ProcessorDefinition> outputs = getParentOutputs(output.getParent()); + if (outputs != null) { + int index = outputs.indexOf(output); if (index != -1) { match = true; - parent.getOutputs().add(index + 1, replace); - Object old = parent.getOutputs().remove(index); + outputs.add(index + 1, replace); + Object old = outputs.remove(index); LOG.info("AdviceWith (" + matchBy.getId() + ") : [" + old + "] --> replace [" + replace + "]"); } } @@ -192,12 +192,12 @@ public final class AdviceWithTasks { while (it.hasNext()) { ProcessorDefinition<?> output = it.next(); if (matchBy.match(output)) { - ProcessorDefinition<?> parent = output.getParent(); - if (parent != null) { - int index = parent.getOutputs().indexOf(output); + List<ProcessorDefinition> outputs = getParentOutputs(output.getParent()); + if (outputs != null) { + int index = outputs.indexOf(output); if (index != -1) { match = true; - Object old = parent.getOutputs().remove(index); + Object old = outputs.remove(index); LOG.info("AdviceWith (" + matchBy.getId() + ") : [" + old + "] --> remove"); } } @@ -240,13 +240,13 @@ public final class AdviceWithTasks { while (it.hasNext()) { ProcessorDefinition<?> output = it.next(); if (matchBy.match(output)) { - ProcessorDefinition<?> parent = output.getParent(); - if (parent != null) { - int index = parent.getOutputs().indexOf(output); + List<ProcessorDefinition> outputs = getParentOutputs(output.getParent()); + if (outputs != null) { + int index = outputs.indexOf(output); if (index != -1) { match = true; - Object existing = parent.getOutputs().get(index); - parent.getOutputs().add(index, before); + Object existing = outputs.get(index); + outputs.add(index, before); LOG.info("AdviceWith (" + matchBy.getId() + ") : [" + existing + "] --> before [" + before + "]"); } } @@ -289,14 +289,13 @@ public final class AdviceWithTasks { while (it.hasNext()) { ProcessorDefinition<?> output = it.next(); if (matchBy.match(output)) { - - ProcessorDefinition<?> parent = output.getParent(); - if (parent != null) { - int index = parent.getOutputs().indexOf(output); + List<ProcessorDefinition> outputs = getParentOutputs(output.getParent()); + if (outputs != null) { + int index = outputs.indexOf(output); if (index != -1) { match = true; - Object existing = parent.getOutputs().get(index); - parent.getOutputs().add(index + 1, after); + Object existing = outputs.get(index); + outputs.add(index + 1, after); LOG.info("AdviceWith (" + matchBy.getId() + ") : [" + existing + "] --> after [" + after + "]"); } } @@ -310,6 +309,30 @@ public final class AdviceWithTasks { }; } + /** + * Gets the outputs from the given parent. + * <p/> + * This implementation deals with that outputs can be abstract and retrieves the correct non-nested output. + * + * @param parent the parent + * @return <tt>null</tt> if no parent + */ + @SuppressWarnings("unchecked") + private static List<ProcessorDefinition> getParentOutputs(ProcessorDefinition parent) { + if (parent == null) { + return null; + } + List<ProcessorDefinition> outputs = parent.getOutputs(); + if (outputs.size() >= 1) { + // if the 1st output is abstract, then its onException,transacted,intercept etc so we should + // get the 'actual' outputs from that + if (outputs.get(0).isAbstract()) { + outputs = outputs.get(0).getOutputs(); + } + } + return outputs; + } + public static AdviceWithTask replaceFromWith(final RouteDefinition route, final String uri) { return new AdviceWithTask() { public void task() throws Exception { @@ -367,7 +390,7 @@ public final class AdviceWithTasks { } private static Iterator<ProcessorDefinition<?>> createSelectorIterator(final List<ProcessorDefinition<?>> list, final boolean selectFirst, - final boolean selectLast, final int selectFrom, final int selectTo) { + final boolean selectLast, final int selectFrom, final int selectTo) { return new Iterator<ProcessorDefinition<?>>() { private int current; private boolean done; http://git-wip-us.apache.org/repos/asf/camel/blob/70f15415/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinitionHelper.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinitionHelper.java b/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinitionHelper.java index 6395ec6..5575d36 100644 --- a/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinitionHelper.java +++ b/camel-core/src/main/java/org/apache/camel/model/ProcessorDefinitionHelper.java @@ -243,6 +243,16 @@ public final class ProcessorDefinitionHelper { continue; } + // special for some types which has special outputs + if (out instanceof OutputDefinition) { + OutputDefinition outDef = (OutputDefinition) out; + List<ProcessorDefinition<?>> outDefOut = outDef.getOutputs(); + doFindType(outDefOut, type, found); + + // do not check children as we already did that + continue; + } + // try children as well List<ProcessorDefinition<?>> children = out.getOutputs(); doFindType(children, type, found); http://git-wip-us.apache.org/repos/asf/camel/blob/70f15415/camel-core/src/test/java/org/apache/camel/issues/AdviceWithPolicyTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/issues/AdviceWithPolicyTest.java b/camel-core/src/test/java/org/apache/camel/issues/AdviceWithPolicyTest.java new file mode 100644 index 0000000..c4a3416 --- /dev/null +++ b/camel-core/src/test/java/org/apache/camel/issues/AdviceWithPolicyTest.java @@ -0,0 +1,78 @@ +/** + * 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.Processor; +import org.apache.camel.builder.AdviceWithRouteBuilder; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.model.ProcessorDefinition; +import org.apache.camel.model.RouteDefinition; +import org.apache.camel.spi.Policy; +import org.apache.camel.spi.RouteContext; + +/** + * @version + */ +public class AdviceWithPolicyTest extends ContextTestSupport { + + public void testAdviceWithPolicy() throws Exception { + RouteDefinition route = context.getRouteDefinitions().get(0); + route.adviceWith(context, new AdviceWithRouteBuilder() { + @Override + public void configure() throws Exception { + weaveById("b").after().to("mock:result"); + } + }); + context.start(); + + getMockEndpoint("mock:a").expectedMessageCount(1); + getMockEndpoint("mock:b").expectedMessageCount(1); + getMockEndpoint("mock:result").expectedMessageCount(1); + + template.sendBody("direct:start", "Hello World"); + + assertMockEndpointsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:start") + .policy(new MyPolicy()) + .to("mock:a").id("a") + .to("mock:b").id("b"); + } + }; + } + + private static final class MyPolicy implements Policy { + + @Override + public void beforeWrap(RouteContext routeContext, ProcessorDefinition<?> definition) { + // noop + } + + @Override + public Processor wrap(RouteContext routeContext, Processor processor) { + return processor; + } + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/70f15415/components/camel-spring/src/test/java/org/apache/camel/spring/issues/AdviceWithTransactionIssueTest.java ---------------------------------------------------------------------- diff --git a/components/camel-spring/src/test/java/org/apache/camel/spring/issues/AdviceWithTransactionIssueTest.java b/components/camel-spring/src/test/java/org/apache/camel/spring/issues/AdviceWithTransactionIssueTest.java new file mode 100644 index 0000000..89d6067 --- /dev/null +++ b/components/camel-spring/src/test/java/org/apache/camel/spring/issues/AdviceWithTransactionIssueTest.java @@ -0,0 +1,76 @@ +/** + * 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.issues; + +import org.apache.camel.builder.AdviceWithRouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.spring.SpringTestSupport; +import org.junit.Test; +import org.springframework.context.support.AbstractXmlApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +public class AdviceWithTransactionIssueTest extends SpringTestSupport { + + @Override + public boolean isUseRouteBuilder() { + return false; + } + + @Override + protected AbstractXmlApplicationContext createApplicationContext() { + return new ClassPathXmlApplicationContext("org/apache/camel/spring/issues/AdviceWithTransactionIssueTest.xml"); + } + + @Test + public void testAdviceWithWeaveById() throws Exception { + context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() { + @Override + public void configure() throws Exception { + weaveById("mock-b*").after().to("mock:last"); + } + }); + context.start(); + + MockEndpoint mockLast = getMockEndpoint("mock:last"); + mockLast.expectedBodiesReceived("bar"); + mockLast.setExpectedMessageCount(1); + + template.sendBody("seda:start", "bar"); + + assertMockEndpointsSatisfied(); + } + + @Test + public void testAdviceWithAddLast() throws Exception { + context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() { + @Override + public void configure() throws Exception { + weaveAddLast().to("mock:last"); + } + }); + context.start(); + + MockEndpoint mockLast = getMockEndpoint("mock:last"); + mockLast.expectedBodiesReceived("bar"); + mockLast.setExpectedMessageCount(1); + + template.sendBody("seda:start", "bar"); + + assertMockEndpointsSatisfied(); + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/70f15415/components/camel-spring/src/test/resources/org/apache/camel/spring/issues/AdviceWithTransactionIssueTest.xml ---------------------------------------------------------------------- diff --git a/components/camel-spring/src/test/resources/org/apache/camel/spring/issues/AdviceWithTransactionIssueTest.xml b/components/camel-spring/src/test/resources/org/apache/camel/spring/issues/AdviceWithTransactionIssueTest.xml new file mode 100644 index 0000000..1d4bcb2 --- /dev/null +++ b/components/camel-spring/src/test/resources/org/apache/camel/spring/issues/AdviceWithTransactionIssueTest.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation=" + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd + "> + + <import resource="../interceptor/transactionalClientDataSource.xml"/> + + <camelContext id="myCamelContext" xmlns="http://camel.apache.org/schema/spring"> + <route id="route1"> + <from uri="seda:start"/> + <transacted/> + <to id="mock-a" uri="mock:a"/> + <to id="mock-b" uri="mock:b"/> + </route> + </camelContext> +</beans> http://git-wip-us.apache.org/repos/asf/camel/blob/70f15415/tests/camel-itest/src/test/java/org/apache/camel/itest/jms/AdviceWithTransactionIssueTest.java ---------------------------------------------------------------------- diff --git a/tests/camel-itest/src/test/java/org/apache/camel/itest/jms/AdviceWithTransactionIssueTest.java b/tests/camel-itest/src/test/java/org/apache/camel/itest/jms/AdviceWithTransactionIssueTest.java new file mode 100644 index 0000000..73163d9 --- /dev/null +++ b/tests/camel-itest/src/test/java/org/apache/camel/itest/jms/AdviceWithTransactionIssueTest.java @@ -0,0 +1,76 @@ +/** + * 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.itest.jms; + +import org.apache.camel.builder.AdviceWithRouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.spring.CamelSpringTestSupport; +import org.apache.xbean.spring.context.ClassPathXmlApplicationContext; +import org.junit.Test; +import org.springframework.context.support.AbstractApplicationContext; + +public class AdviceWithTransactionIssueTest extends CamelSpringTestSupport { + + @Override + protected AbstractApplicationContext createApplicationContext() { + return new ClassPathXmlApplicationContext("org/apache/camel/itest/jms/AdviceWithTransactionIssueTest.xml"); + } + + @Override + public boolean isUseAdviceWith() { + return true; + } + + @Test + public void testAdviceWithWeaveById() throws Exception { + context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() { + @Override + public void configure() throws Exception { + weaveById("mock-b*").after().to("mock:last"); + } + }); + context.start(); + + MockEndpoint mockLast = getMockEndpoint("mock:last"); + mockLast.expectedBodiesReceived("bar"); + mockLast.setExpectedMessageCount(1); + + template.sendBody("activemq:queue:start", "bar"); + + assertMockEndpointsSatisfied(); + } + + @Test + public void testAdviceWithAddLast() throws Exception { + context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() { + @Override + public void configure() throws Exception { + weaveAddLast().to("mock:last"); + } + }); + context.start(); + + MockEndpoint mockLast = getMockEndpoint("mock:last"); + mockLast.expectedBodiesReceived("bar"); + mockLast.setExpectedMessageCount(1); + + template.sendBody("activemq:queue:start", "bar"); + + assertMockEndpointsSatisfied(); + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/70f15415/tests/camel-itest/src/test/resources/org/apache/camel/itest/jms/AdviceWithTransactionIssueTest.xml ---------------------------------------------------------------------- diff --git a/tests/camel-itest/src/test/resources/org/apache/camel/itest/jms/AdviceWithTransactionIssueTest.xml b/tests/camel-itest/src/test/resources/org/apache/camel/itest/jms/AdviceWithTransactionIssueTest.xml new file mode 100644 index 0000000..8f145ff --- /dev/null +++ b/tests/camel-itest/src/test/resources/org/apache/camel/itest/jms/AdviceWithTransactionIssueTest.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation=" + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd"> + + <bean id="poolConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory"> + <property name="maxConnections" value="8"/> + <property name="connectionFactory" ref="jmsConnectionFactory"/> + </bean> + + <bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> + <property name="brokerURL" value="vm://localhost?broker.persistent=false&broker.useJmx=false"/> + </bean> + + <bean id="jmsTransactionManager" class="org.springframework.jms.connection.JmsTransactionManager"> + <property name="connectionFactory" ref="poolConnectionFactory"/> + </bean> + + <bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent"> + <property name="connectionFactory" ref="poolConnectionFactory"/> + <property name="transacted" value="true"/> + <property name="transactionManager" ref="jmsTransactionManager"/> + <!-- we do not want any exceptions to be logged --> + <property name="errorHandlerLoggingLevel" value="OFF"/> + <property name="errorHandlerLogStackTrace" value="false"/> + </bean> + + <camelContext xmlns="http://camel.apache.org/schema/spring"> + + <route id="route1"> + <from uri="activemq:queue:start"/> + <transacted/> + <to id="mock-a" uri="mock:a"/> + <to id="mock-b" uri="mock:b"/> + </route> + + </camelContext> + + +</beans>