Author: jstrachan Date: Wed Sep 5 14:42:52 2012 New Revision: 1381202 URL: http://svn.apache.org/viewvc?rev=1381202&view=rev Log: improved CAMEL-5566 so we can use @CamelStartup on @Produces methods too; for example when reusing a RouteBuilder class multiple times with different configurations/injections
Added: camel/trunk/components/camel-cdi/src/main/java/org/apache/camel/component/cdi/internal/CamelContextConfig.java (with props) camel/trunk/tests/camel-itest-cdi/src/main/java/org/apache/camel/itest/cdi/MyConfig.java (with props) camel/trunk/tests/camel-itest-cdi/src/main/java/org/apache/camel/itest/cdi/MyRouteBuilder.java (with props) Modified: camel/trunk/components/camel-cdi/src/main/java/org/apache/camel/component/cdi/internal/CamelContextBean.java camel/trunk/components/camel-cdi/src/main/java/org/apache/camel/component/cdi/internal/CamelExtension.java camel/trunk/tests/camel-itest-cdi/src/main/java/org/apache/camel/itest/cdi/Constants.java camel/trunk/tests/camel-itest-cdi/src/test/java/org/apache/camel/itest/cdi/IntegrationTest.java Modified: camel/trunk/components/camel-cdi/src/main/java/org/apache/camel/component/cdi/internal/CamelContextBean.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-cdi/src/main/java/org/apache/camel/component/cdi/internal/CamelContextBean.java?rev=1381202&r1=1381201&r2=1381202&view=diff ============================================================================== --- camel/trunk/components/camel-cdi/src/main/java/org/apache/camel/component/cdi/internal/CamelContextBean.java (original) +++ camel/trunk/components/camel-cdi/src/main/java/org/apache/camel/component/cdi/internal/CamelContextBean.java Wed Sep 5 14:42:52 2012 @@ -47,19 +47,19 @@ public class CamelContextBean implements private final BeanManager beanManager; private final String name; private final String camelContextName; - private final List<Bean<?>> routeBuilderBeans; private final InjectionTarget<CdiCamelContext> target; + private final CamelContextConfig config; public CamelContextBean(BeanManager beanManager) { - this(beanManager, "CamelContext", "", Collections.EMPTY_LIST); + this(beanManager, "CamelContext", "", new CamelContextConfig()); } public CamelContextBean(BeanManager beanManager, String name, String camelContextName, - List<Bean<?>> routeBuilderBeans) { + CamelContextConfig config) { this.beanManager = beanManager; this.name = name; this.camelContextName = camelContextName; - this.routeBuilderBeans = routeBuilderBeans; + this.config = config; this.target = beanManager.createInjectionTarget(beanManager.createAnnotatedType(CdiCamelContext.class)); } @@ -131,14 +131,6 @@ public class CamelContextBean implements } public void configureCamelContext(CdiCamelContext camelContext) { - for (Bean<?> bean : routeBuilderBeans) { - CreationalContext<?> creationalContext = beanManager.createCreationalContext(bean); - RouteBuilder routeBuilder = (RouteBuilder)beanManager.getReference(bean, RouteBuilder.class, creationalContext); - try { - camelContext.addRoutes(routeBuilder); - } catch (Exception e) { - throw new RuntimeCamelException("Could not add route builder " + routeBuilder + ". Reason: " + e, e); - } - } + config.configure(camelContext, beanManager); } } Added: camel/trunk/components/camel-cdi/src/main/java/org/apache/camel/component/cdi/internal/CamelContextConfig.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-cdi/src/main/java/org/apache/camel/component/cdi/internal/CamelContextConfig.java?rev=1381202&view=auto ============================================================================== --- camel/trunk/components/camel-cdi/src/main/java/org/apache/camel/component/cdi/internal/CamelContextConfig.java (added) +++ camel/trunk/components/camel-cdi/src/main/java/org/apache/camel/component/cdi/internal/CamelContextConfig.java Wed Sep 5 14:42:52 2012 @@ -0,0 +1,53 @@ +/** + * + * 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.component.cdi.internal; + +import java.util.ArrayList; +import java.util.List; +import javax.enterprise.context.spi.Contextual; +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.Producer; + +import org.apache.camel.RuntimeCamelException; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.cdi.CdiCamelContext; + +/** + * Configuration options to be applied to a {@link CamelContext} by a {@link CamelContextBean} + */ +public class CamelContextConfig { + private final List<Bean<?>> routeBuilderBeans = new ArrayList<Bean<?>>(); + + public void addRouteBuilderBean(Bean<?> bean) { + routeBuilderBeans.add(bean); + } + + public void configure(CdiCamelContext camelContext, BeanManager beanManager) { + for (Bean<?> bean : routeBuilderBeans) { + CreationalContext<?> createContext = beanManager.createCreationalContext(bean); + RouteBuilder routeBuilder = (RouteBuilder)beanManager.getReference(bean, RouteBuilder.class, createContext); + try { + camelContext.addRoutes(routeBuilder); + } catch (Exception e) { + throw new RuntimeCamelException("Could not add route builder " + routeBuilder + ". Reason: " + e, e); + } + } + } +} Propchange: camel/trunk/components/camel-cdi/src/main/java/org/apache/camel/component/cdi/internal/CamelContextConfig.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: camel/trunk/components/camel-cdi/src/main/java/org/apache/camel/component/cdi/internal/CamelExtension.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-cdi/src/main/java/org/apache/camel/component/cdi/internal/CamelExtension.java?rev=1381202&r1=1381201&r2=1381202&view=diff ============================================================================== --- camel/trunk/components/camel-cdi/src/main/java/org/apache/camel/component/cdi/internal/CamelExtension.java (original) +++ camel/trunk/components/camel-cdi/src/main/java/org/apache/camel/component/cdi/internal/CamelExtension.java Wed Sep 5 14:42:52 2012 @@ -28,6 +28,7 @@ import javax.enterprise.context.spi.Crea import javax.enterprise.event.Observes; import javax.enterprise.inject.spi.AfterBeanDiscovery; import javax.enterprise.inject.spi.AfterDeploymentValidation; +import javax.enterprise.inject.spi.Annotated; import javax.enterprise.inject.spi.AnnotatedType; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; @@ -36,6 +37,7 @@ import javax.enterprise.inject.spi.Injec import javax.enterprise.inject.spi.ProcessAnnotatedType; import javax.enterprise.inject.spi.ProcessBean; import javax.enterprise.inject.spi.ProcessInjectionTarget; +import javax.enterprise.inject.spi.ProcessProducerMethod; import javax.inject.Inject; import org.apache.camel.CamelContext; @@ -60,7 +62,7 @@ public class CamelExtension implements E CamelContextMap camelContextMap; private Set<Bean<?>> eagerBeans = new HashSet<Bean<?>>(); - private Map<String, List<Bean<?>>> namedCamelContexts = new HashMap<String, List<Bean<?>>>(); + private Map<String, CamelContextConfig> camelContextConfigMap = new HashMap<String, CamelContextConfig>(); private List<CamelContextBean> camelContextBeans = new ArrayList<CamelContextBean>(); public CamelExtension() { @@ -83,7 +85,7 @@ public class CamelExtension implements E * @throws Exception In case of exceptions. */ protected void contextAwareness(@Observes ProcessAnnotatedType<CamelContextAware> process) - throws Exception { + throws Exception { AnnotatedType<CamelContextAware> annotatedType = process.getAnnotatedType(); Class<CamelContextAware> javaClass = annotatedType.getJavaClass(); if (CamelContextAware.class.isAssignableFrom(javaClass)) { @@ -113,14 +115,15 @@ public class CamelExtension implements E */ protected void registerManagedCamelContext(@Observes AfterBeanDiscovery abd, BeanManager manager) { // lets ensure we have at least one camel context - if (namedCamelContexts.isEmpty()) { + if (camelContextConfigMap.isEmpty()) { abd.addBean(new CamelContextBean(manager)); } else { - Set<Map.Entry<String, List<Bean<?>>>> entries = namedCamelContexts.entrySet(); - for (Map.Entry<String, List<Bean<?>>> entry : entries) { + Set<Map.Entry<String, CamelContextConfig>> entries = camelContextConfigMap.entrySet(); + for (Map.Entry<String, CamelContextConfig> entry : entries) { String name = entry.getKey(); - List<Bean<?>> beans = entry.getValue(); - CamelContextBean camelContextBean = new CamelContextBean(manager, "CamelContext:" + name, name, beans); + CamelContextConfig config = entry.getValue(); + CamelContextBean camelContextBean = new CamelContextBean(manager, "CamelContext:" + name, + name, config); camelContextBeans.add(camelContextBean); abd.addBean(camelContextBean); } @@ -144,31 +147,57 @@ public class CamelExtension implements E } } }); + } - // detect all RouteBuilder instances + /** + * Lets detect all beans annotated of type {@link RouteBuilder} + * which are annotated with {@link org.apache.camel.cdi.CamelStartup} + * so they can be auto-registered + */ + public void detectRouteBuilderBeans(@Observes ProcessBean<?> event) { + final Bean<?> bean = event.getBean(); + Class<?> beanClass = bean.getBeanClass(); if (RouteBuilder.class.isAssignableFrom(beanClass)) { - CamelStartup annotation = beanClass.getAnnotation(CamelStartup.class); - if (annotation != null) { - String contextName = annotation.contextName(); - List<Bean<?>> beans = namedCamelContexts.get(contextName); - if (beans == null) { - beans = new ArrayList<Bean<?>>(); - namedCamelContexts.put(contextName, beans); - } - beans.add(bean); + addRouteBuilderBean(bean, beanClass.getAnnotation(CamelStartup.class)); + } + } + + private void addRouteBuilderBean(Bean<?> bean, CamelStartup annotation) { + if (annotation != null) { + String contextName = annotation.contextName(); + CamelContextConfig config = camelContextConfigMap.get(contextName); + if (config == null) { + config = new CamelContextConfig(); + camelContextConfigMap.put(contextName, config); } + config.addRouteBuilderBean(bean); + } + } + + /** + * Lets detect all producer methods createing instances of {@link RouteBuilder} which are annotated with {@link org.apache.camel.cdi.CamelStartup} + * so they can be auto-registered + */ + public void detectProducerRoutes(@Observes ProcessProducerMethod<?, ?> event) { + Annotated annotated = event.getAnnotated(); + CamelStartup annotation = annotated.getAnnotation(CamelStartup.class); + Class<?> returnType = event.getAnnotatedProducerMethod().getJavaMember().getReturnType(); + if (RouteBuilder.class.isAssignableFrom(returnType)) { + addRouteBuilderBean(event.getBean(), annotation); } } /** * Lets force the CDI container to create all beans annotated with @Consume so that the consumer becomes active */ - public void startConsumeBeans(@Observes AfterDeploymentValidation event, BeanManager beanManager) throws Exception { + public void startConsumeBeans(@Observes AfterDeploymentValidation event, BeanManager beanManager) + throws Exception { for (CamelContextBean bean : camelContextBeans) { String name = bean.getCamelContextName(); CamelContext context = getCamelContext(name); if (context == null) { - throw new IllegalStateException("CamelContext '" + name + "' has not been injected into the CamelContextMap"); + throw new IllegalStateException( + "CamelContext '" + name + "' has not been injected into the CamelContextMap"); } bean.configureCamelContext((CdiCamelContext)context); } @@ -210,7 +239,7 @@ public class CamelExtension implements E /** * Perform injection on an existing bean such as a test case which is created directly by a testing framework. - * + * <p/> * This is because BeanProvider.injectFields() does not invoke the onInjectionTarget() method so the injection * of @Produce / @EndpointInject and processing of the @Consume annotations are not performed. */ Modified: camel/trunk/tests/camel-itest-cdi/src/main/java/org/apache/camel/itest/cdi/Constants.java URL: http://svn.apache.org/viewvc/camel/trunk/tests/camel-itest-cdi/src/main/java/org/apache/camel/itest/cdi/Constants.java?rev=1381202&r1=1381201&r2=1381202&view=diff ============================================================================== --- camel/trunk/tests/camel-itest-cdi/src/main/java/org/apache/camel/itest/cdi/Constants.java (original) +++ camel/trunk/tests/camel-itest-cdi/src/main/java/org/apache/camel/itest/cdi/Constants.java Wed Sep 5 14:42:52 2012 @@ -22,4 +22,7 @@ public class Constants { public static Object[] EXPECTED_BODIES_B = {"messageB1", "messageB2"}; public static Object[] EXPECTED_BODIES_C = {"messageC1", "messageC2"}; public static Object[] EXPECTED_BODIES_D = {"messageD1", "messageD2"}; + + public static Object[] EXPECTED_BODIES_Ea = {"messageEa1", "messageEa2"}; + public static Object[] EXPECTED_BODIES_Ec = {"messageEc1", "messageEc2"}; } Added: camel/trunk/tests/camel-itest-cdi/src/main/java/org/apache/camel/itest/cdi/MyConfig.java URL: http://svn.apache.org/viewvc/camel/trunk/tests/camel-itest-cdi/src/main/java/org/apache/camel/itest/cdi/MyConfig.java?rev=1381202&view=auto ============================================================================== --- camel/trunk/tests/camel-itest-cdi/src/main/java/org/apache/camel/itest/cdi/MyConfig.java (added) +++ camel/trunk/tests/camel-itest-cdi/src/main/java/org/apache/camel/itest/cdi/MyConfig.java Wed Sep 5 14:42:52 2012 @@ -0,0 +1,41 @@ +/** + * + * 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.cdi; + +import javax.enterprise.inject.Produces; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.cdi.CamelStartup; + +/** + * Instantiate a number of route builders using + */ +public class MyConfig { + + @Produces + @CamelStartup(contextName = "contextE") + public RouteBuilder createRouteA() { + return new MyRouteBuilder("seda:E.a", "mock:E.b"); + } + + @Produces + @CamelStartup(contextName = "contextE") + public RouteBuilder createRouteB() { + return new MyRouteBuilder("seda:E.c", "mock:E.d"); + } +} Propchange: camel/trunk/tests/camel-itest-cdi/src/main/java/org/apache/camel/itest/cdi/MyConfig.java ------------------------------------------------------------------------------ svn:eol-style = native Added: camel/trunk/tests/camel-itest-cdi/src/main/java/org/apache/camel/itest/cdi/MyRouteBuilder.java URL: http://svn.apache.org/viewvc/camel/trunk/tests/camel-itest-cdi/src/main/java/org/apache/camel/itest/cdi/MyRouteBuilder.java?rev=1381202&view=auto ============================================================================== --- camel/trunk/tests/camel-itest-cdi/src/main/java/org/apache/camel/itest/cdi/MyRouteBuilder.java (added) +++ camel/trunk/tests/camel-itest-cdi/src/main/java/org/apache/camel/itest/cdi/MyRouteBuilder.java Wed Sep 5 14:42:52 2012 @@ -0,0 +1,44 @@ +/** + * + * 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.cdi; + +import org.apache.camel.builder.RouteBuilder; + +/** + * An example configurable {@link RouteBuilder} + */ +public class MyRouteBuilder extends RouteBuilder { + private final String a; + private final String b; + + public MyRouteBuilder(String a, String b) { + this.a = a; + this.b = b; + } + + @Override + public String toString() { + return "MyRouteBuilder(" + a + " -> " + b + ")"; + + } + + @Override + public void configure() throws Exception { + from(a).to(b); + } +} Propchange: camel/trunk/tests/camel-itest-cdi/src/main/java/org/apache/camel/itest/cdi/MyRouteBuilder.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: camel/trunk/tests/camel-itest-cdi/src/test/java/org/apache/camel/itest/cdi/IntegrationTest.java URL: http://svn.apache.org/viewvc/camel/trunk/tests/camel-itest-cdi/src/test/java/org/apache/camel/itest/cdi/IntegrationTest.java?rev=1381202&r1=1381201&r2=1381202&view=diff ============================================================================== --- camel/trunk/tests/camel-itest-cdi/src/test/java/org/apache/camel/itest/cdi/IntegrationTest.java (original) +++ camel/trunk/tests/camel-itest-cdi/src/test/java/org/apache/camel/itest/cdi/IntegrationTest.java Wed Sep 5 14:42:52 2012 @@ -22,9 +22,12 @@ import javax.inject.Inject; import org.apache.camel.CamelContext; import org.apache.camel.Endpoint; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.cdi.Uri; import org.apache.camel.component.cdi.internal.CamelContextMap; import org.apache.camel.component.cdi.internal.CamelExtension; import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.util.CamelContextHelper; import org.jboss.arquillian.container.test.api.Deployment; import org.jboss.arquillian.junit.Arquillian; import org.jboss.shrinkwrap.api.ShrinkWrap; @@ -53,6 +56,9 @@ public class IntegrationTest { @Inject RoutesContextD routesD; + @Inject @Uri(value="seda:foo", context = "contextE") + ProducerTemplate producerE; + @Test public void checkContextsHaveCorrectEndpointsAndRoutes() throws Exception { Set<Map.Entry<String,CamelContext>> entries = camelContextMap.getCamelContextMap().entrySet(); @@ -77,6 +83,7 @@ public class IntegrationTest { routesB.sendMessages(); mockEndpointB.assertIsSatisfied(); + // lets check the routes where we default the context from the @CamelStartup CamelContext contextC = assertCamelContext("contextC"); assertHasEndpoints(contextC, "seda://C.a", "mock://C.b"); @@ -92,6 +99,30 @@ public class IntegrationTest { mockEndpointD.expectedBodiesReceived(Constants.EXPECTED_BODIES_D); routesD.sendMessages(); mockEndpointD.assertIsSatisfied(); + + // lets check the 2 routes created using @CamelStartup on a @Produces method + CamelContext contextE = assertCamelContext("contextE"); + assertHasEndpoints(contextE, "seda://E.a", "mock://E.b", "seda://E.c", "mock://E.d"); + + MockEndpoint mockEb = CamelContextHelper + .getMandatoryEndpoint(contextE, "mock://E.b", MockEndpoint.class); + MockEndpoint mockEd = CamelContextHelper + .getMandatoryEndpoint(contextE, "mock://E.d", MockEndpoint.class); + + + mockEb.expectedBodiesReceived(Constants.EXPECTED_BODIES_Ea); + mockEd.expectedBodiesReceived(Constants.EXPECTED_BODIES_Ec); + + for (Object body : Constants.EXPECTED_BODIES_Ea) { + producerE.sendBody("seda:E.a", body); + } + + for (Object body : Constants.EXPECTED_BODIES_Ec) { + producerE.sendBody("seda:E.c", body); + } + + mockEb.assertIsSatisfied(); + mockEd.assertIsSatisfied(); } public static void assertHasEndpoints(CamelContext context, String... uris) {