CAMEL-6463: camel-spring should add routes later to ensure spring dependency injection is fully done, to allow wiring in spring beans in RouteBuilder classes. Thanks to Daniel Cook for the solution.
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/65170906 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/65170906 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/65170906 Branch: refs/heads/master Commit: 65170906077b6d7af0c777200bff1385920f42d5 Parents: f0d6ce3 Author: Claus Ibsen <davscl...@apache.org> Authored: Tue Jul 23 09:11:58 2013 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Tue Jul 23 09:11:58 2013 +0200 ---------------------------------------------------------------------- .../blueprint/CamelContextFactoryBean.java | 3 +- .../xml/AbstractCamelContextFactoryBean.java | 37 +++++++++++++------- .../camel/spring/CamelContextFactoryBean.java | 12 +++++++ .../SpringCamelContextNoDependsOnTest.java | 4 +-- .../spring/config/SpringRouteNoFromTest.java | 2 +- .../spring/config/SpringRouteNoOutputTest.java | 2 +- .../spring/issues/MisspelledRouteRefTest.java | 6 ++-- 7 files changed, 47 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/65170906/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java ---------------------------------------------------------------------- diff --git a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java index 027cc83..1e71c62 100644 --- a/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java +++ b/components/camel-blueprint/src/main/java/org/apache/camel/blueprint/CamelContextFactoryBean.java @@ -167,7 +167,6 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Blu @XmlTransient private boolean implicitId; - public Class<BlueprintCamelContext> getObjectType() { return BlueprintCamelContext.class; } @@ -297,6 +296,8 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Blu // Ignore, if the EventAdmin package is not available, just don't use it LOG.debug("EventAdmin package is not available, just don't use it"); } + // ensure routes is setup + setupRoutes(); } public String getDependsOn() { http://git-wip-us.apache.org/repos/asf/camel/blob/65170906/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java ---------------------------------------------------------------------- diff --git a/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java b/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java index 9fb8d9e..df369a5 100644 --- a/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java +++ b/components/camel-core-xml/src/main/java/org/apache/camel/core/xml/AbstractCamelContextFactoryBean.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlTransient; @@ -111,6 +112,8 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex private List<RoutesBuilder> builders = new ArrayList<RoutesBuilder>(); @XmlTransient private ClassLoader contextClassLoaderOnStart; + @XmlTransient + private final AtomicBoolean routesSetupDone = new AtomicBoolean(); public AbstractCamelContextFactoryBean() { // Keep track of the class loader for when we actually do start things up @@ -269,22 +272,31 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex // init stream caching strategy initStreamCachingStrategy(); + } - // must init route refs before we prepare the routes below - initRouteRefs(); + /** + * Setup all the routes which must be done prior starting {@link CamelContext}. + */ + protected void setupRoutes() throws Exception { + if (routesSetupDone.compareAndSet(false, true)) { + LOG.debug("Setting up routes"); - // do special preparation for some concepts such as interceptors and policies - // this is needed as JAXB does not build exactly the same model definition as Spring DSL would do - // using route builders. So we have here a little custom code to fix the JAXB gaps - prepareRoutes(); + // must init route refs before we prepare the routes below + initRouteRefs(); - // and add the routes - getContext().addRouteDefinitions(getRoutes()); + // do special preparation for some concepts such as interceptors and policies + // this is needed as JAXB does not build exactly the same model definition as Spring DSL would do + // using route builders. So we have here a little custom code to fix the JAXB gaps + prepareRoutes(); - LOG.debug("Found JAXB created routes: {}", getRoutes()); - - findRouteBuilders(); - installRoutes(); + // and add the routes + getContext().addRouteDefinitions(getRoutes()); + + LOG.debug("Found JAXB created routes: {}", getRoutes()); + + findRouteBuilders(); + installRoutes(); + } } /** @@ -485,6 +497,7 @@ public abstract class AbstractCamelContextFactoryBean<T extends ModelCamelContex protected abstract <S> S getBeanForType(Class<S> clazz); public void destroy() throws Exception { + routesSetupDone.set(false); getContext().stop(); } http://git-wip-us.apache.org/repos/asf/camel/blob/65170906/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java ---------------------------------------------------------------------- diff --git a/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java b/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java index b25b329..1ba3163 100644 --- a/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java +++ b/components/camel-spring/src/main/java/org/apache/camel/spring/CamelContextFactoryBean.java @@ -288,6 +288,15 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr SpringCamelContext context = getContext(false); if (context != null) { + // we need to defer setting up routes until Spring has done all its dependency injection + // which is only guaranteed to be done when it emits the ContextRefreshedEvent event. + if (event instanceof ContextRefreshedEvent) { + try { + setupRoutes(); + } catch (Exception e) { + throw wrapRuntimeCamelException(e); + } + } // let the spring camel context handle the events context.onApplicationEvent(event); } else { @@ -297,6 +306,9 @@ public class CamelContextFactoryBean extends AbstractCamelContextFactoryBean<Spr // now lets start the CamelContext so that all its possible // dependencies are initialized try { + // we need to defer setting up routes until Spring has done all its dependency injection + // which is only guaranteed to be done when it emits the ContextRefreshedEvent event. + setupRoutes(); LOG.trace("Starting the context now"); getContext().start(); } catch (Exception e) { http://git-wip-us.apache.org/repos/asf/camel/blob/65170906/components/camel-spring/src/test/java/org/apache/camel/spring/config/SpringCamelContextNoDependsOnTest.java ---------------------------------------------------------------------- diff --git a/components/camel-spring/src/test/java/org/apache/camel/spring/config/SpringCamelContextNoDependsOnTest.java b/components/camel-spring/src/test/java/org/apache/camel/spring/config/SpringCamelContextNoDependsOnTest.java index c277a5e..1da5c22 100644 --- a/components/camel-spring/src/test/java/org/apache/camel/spring/config/SpringCamelContextNoDependsOnTest.java +++ b/components/camel-spring/src/test/java/org/apache/camel/spring/config/SpringCamelContextNoDependsOnTest.java @@ -37,11 +37,11 @@ public class SpringCamelContextNoDependsOnTest extends SpringTestSupport { assertMockEndpointsSatisfied(); - // in this example CamelContext is created first, then route builder, and then the depends on bean is last + // in this example the depends on bean is created first, and then the route builder, and CamelContext is started last. long time1 = context.getRegistry().lookupByNameAndType("myDependsOnBean", MyDependsOnBean.class).getTime(); long time2 = context.getRegistry().lookupByNameAndType("myRouteBuilder", MyDependsOnRouteBuilder.class).getTime(); - assertTrue("myDependsOnBean should NOT be created before myRouteBuilder", time1 > time2); + assertTrue("myDependsOnBean should be created before myRouteBuilder", time2 > time1); } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/65170906/components/camel-spring/src/test/java/org/apache/camel/spring/config/SpringRouteNoFromTest.java ---------------------------------------------------------------------- diff --git a/components/camel-spring/src/test/java/org/apache/camel/spring/config/SpringRouteNoFromTest.java b/components/camel-spring/src/test/java/org/apache/camel/spring/config/SpringRouteNoFromTest.java index 6a96595..b4fc035 100644 --- a/components/camel-spring/src/test/java/org/apache/camel/spring/config/SpringRouteNoFromTest.java +++ b/components/camel-spring/src/test/java/org/apache/camel/spring/config/SpringRouteNoFromTest.java @@ -41,7 +41,7 @@ public class SpringRouteNoFromTest extends SpringTestSupport { answer = new ClassPathXmlApplicationContext("org/apache/camel/spring/config/SpringRouteNoFromTest.xml"); fail("Should have thrown exception"); } catch (Exception e) { - IllegalArgumentException iae = (IllegalArgumentException) e.getCause().getCause(); + IllegalArgumentException iae = (IllegalArgumentException) e.getCause(); assertEquals("Route myRoute has no inputs: Route(myRoute)[[] -> [To[mock:result]]]", iae.getMessage()); return null; } http://git-wip-us.apache.org/repos/asf/camel/blob/65170906/components/camel-spring/src/test/java/org/apache/camel/spring/config/SpringRouteNoOutputTest.java ---------------------------------------------------------------------- diff --git a/components/camel-spring/src/test/java/org/apache/camel/spring/config/SpringRouteNoOutputTest.java b/components/camel-spring/src/test/java/org/apache/camel/spring/config/SpringRouteNoOutputTest.java index f3e156f..4ff49a0 100644 --- a/components/camel-spring/src/test/java/org/apache/camel/spring/config/SpringRouteNoOutputTest.java +++ b/components/camel-spring/src/test/java/org/apache/camel/spring/config/SpringRouteNoOutputTest.java @@ -41,7 +41,7 @@ public class SpringRouteNoOutputTest extends SpringTestSupport { answer = new ClassPathXmlApplicationContext("org/apache/camel/spring/config/SpringRouteNoOutputTest.xml"); fail("Should have thrown exception"); } catch (Exception e) { - IllegalArgumentException iae = (IllegalArgumentException) e.getCause().getCause(); + IllegalArgumentException iae = (IllegalArgumentException) e.getCause(); assertEquals("Route myRoute has no outputs: Route(myRoute)[[From[direct:start]] -> []]", iae.getMessage()); return null; } http://git-wip-us.apache.org/repos/asf/camel/blob/65170906/components/camel-spring/src/test/java/org/apache/camel/spring/issues/MisspelledRouteRefTest.java ---------------------------------------------------------------------- diff --git a/components/camel-spring/src/test/java/org/apache/camel/spring/issues/MisspelledRouteRefTest.java b/components/camel-spring/src/test/java/org/apache/camel/spring/issues/MisspelledRouteRefTest.java index 12ea239..f38b936 100644 --- a/components/camel-spring/src/test/java/org/apache/camel/spring/issues/MisspelledRouteRefTest.java +++ b/components/camel-spring/src/test/java/org/apache/camel/spring/issues/MisspelledRouteRefTest.java @@ -17,6 +17,7 @@ package org.apache.camel.spring.issues; import junit.framework.TestCase; +import org.apache.camel.CamelException; import org.apache.camel.spring.Main; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,8 +38,9 @@ public class MisspelledRouteRefTest extends TestCase { } catch (Exception e) { //expected but want to see what it looks like... LOG.debug("Exception message : " + e.getMessage()); - assertTrue("Get a wrong exception name", e.getMessage().indexOf("nested exception is org.apache.camel.CamelException: " - + "Cannot find any routes with this RouteBuilder reference: RouteBuilderRef[xxxroute]") > 0); + + CamelException cause = (CamelException) e.getCause(); + assertEquals("Cannot find any routes with this RouteBuilder reference: RouteBuilderRef[xxxroute]", cause.getMessage()); } } }