Author: jstrachan Date: Mon Feb 28 19:20:56 2011 New Revision: 1075495 URL: http://svn.apache.org/viewvc?rev=1075495&view=rev Log: fix for CAMEL-3726 to show camel-context working using Spring IoC along with solving a dependency issue with CamelPostProcessorHelper causing eager loading of CamelContext objects which breaks the depends-on attribute usage
Added: camel/trunk/components/camel-context/src/test/java/org/apache/camel/component/context/SpringDslContextComponentTest.java camel/trunk/components/camel-context/src/test/resources/org/ camel/trunk/components/camel-context/src/test/resources/org/apache/ camel/trunk/components/camel-context/src/test/resources/org/apache/camel/ camel/trunk/components/camel-context/src/test/resources/org/apache/camel/component/ camel/trunk/components/camel-context/src/test/resources/org/apache/camel/component/context/ camel/trunk/components/camel-context/src/test/resources/org/apache/camel/component/context/SpringDslContextComponentTest-context.xml Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/CamelPostProcessorHelper.java camel/trunk/components/camel-context/pom.xml camel/trunk/components/camel-context/src/main/java/org/apache/camel/component/context/LocalContextComponent.java camel/trunk/components/camel-context/src/test/java/org/apache/camel/component/context/JavaDslBlackBoxTest.java camel/trunk/components/camel-spring/src/main/java/org/apache/camel/spring/CamelBeanPostProcessor.java Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/CamelPostProcessorHelper.java URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/CamelPostProcessorHelper.java?rev=1075495&r1=1075494&r2=1075495&view=diff ============================================================================== --- camel/trunk/camel-core/src/main/java/org/apache/camel/impl/CamelPostProcessorHelper.java (original) +++ camel/trunk/camel-core/src/main/java/org/apache/camel/impl/CamelPostProcessorHelper.java Mon Feb 28 19:20:56 2011 @@ -75,7 +75,7 @@ public class CamelPostProcessorHelper im */ public boolean matchContext(String context) { if (ObjectHelper.isNotEmpty(context)) { - if (!camelContext.getName().equals(context)) { + if (!getCamelContext().getName().equals(context)) { return false; } } Modified: camel/trunk/components/camel-context/pom.xml URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-context/pom.xml?rev=1075495&r1=1075494&r2=1075495&view=diff ============================================================================== --- camel/trunk/components/camel-context/pom.xml (original) +++ camel/trunk/components/camel-context/pom.xml Mon Feb 28 19:20:56 2011 @@ -51,6 +51,11 @@ </dependency> <dependency> <groupId>org.apache.camel</groupId> + <artifactId>camel-core-xml</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.camel</groupId> <artifactId>camel-test</artifactId> <scope>test</scope> </dependency> Modified: camel/trunk/components/camel-context/src/main/java/org/apache/camel/component/context/LocalContextComponent.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-context/src/main/java/org/apache/camel/component/context/LocalContextComponent.java?rev=1075495&r1=1075494&r2=1075495&view=diff ============================================================================== --- camel/trunk/components/camel-context/src/main/java/org/apache/camel/component/context/LocalContextComponent.java (original) +++ camel/trunk/components/camel-context/src/main/java/org/apache/camel/component/context/LocalContextComponent.java Mon Feb 28 19:20:56 2011 @@ -35,7 +35,7 @@ public class LocalContextComponent exten private static final transient Logger LOG = LoggerFactory.getLogger(LocalContextComponent.class); private CamelContext localCamelContext; - private List<String> localProtocolSchemes = new ArrayList<String>(Arrays.asList("direct", "seda")); + private List<String> localProtocolSchemes = new ArrayList<String>(Arrays.asList("direct", "seda", "mock")); public LocalContextComponent(CamelContext localCamelContext) { ObjectHelper.notNull(localCamelContext, "localCamelContext"); @@ -65,8 +65,14 @@ public class LocalContextComponent exten protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception { + + // lets first check if we are using a fully qualified name: [context:]contextId:endpointUri Map<String, Endpoint> map = getLocalCamelContext().getEndpointMap(); + + if (LOG.isDebugEnabled()) { + LOG.debug("Trying to lookup " + remaining + " in local map " + map.keySet()); + } Endpoint endpoint = map.get(remaining); if (endpoint != null) { logUsingEndpoint(uri, endpoint); Modified: camel/trunk/components/camel-context/src/test/java/org/apache/camel/component/context/JavaDslBlackBoxTest.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-context/src/test/java/org/apache/camel/component/context/JavaDslBlackBoxTest.java?rev=1075495&r1=1075494&r2=1075495&view=diff ============================================================================== --- camel/trunk/components/camel-context/src/test/java/org/apache/camel/component/context/JavaDslBlackBoxTest.java (original) +++ camel/trunk/components/camel-context/src/test/java/org/apache/camel/component/context/JavaDslBlackBoxTest.java Mon Feb 28 19:20:56 2011 @@ -38,7 +38,7 @@ public class JavaDslBlackBoxTest extends private ProducerTemplate template; @Test - public void testUsingBlackBox() throws Exception { + public void testUsingContextComponent() throws Exception { resultEndpoint.expectedHeaderReceived("received", "true"); resultEndpoint.expectedMessageCount(2); @@ -58,8 +58,8 @@ public class JavaDslBlackBoxTest extends blackBox.addRoutes(new RouteBuilder() { @Override public void configure() throws Exception { - // receive purchase orders, lets process it in some way then send an invoice - // to our invoice endpoint + // receive purchase orders, lets process it in some way then + // send an invoice to our invoice endpoint from("direct:purchaseOrder").setHeader("received").constant("true").to("direct:invoice"); } }); Added: camel/trunk/components/camel-context/src/test/java/org/apache/camel/component/context/SpringDslContextComponentTest.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-context/src/test/java/org/apache/camel/component/context/SpringDslContextComponentTest.java?rev=1075495&view=auto ============================================================================== --- camel/trunk/components/camel-context/src/test/java/org/apache/camel/component/context/SpringDslContextComponentTest.java (added) +++ camel/trunk/components/camel-context/src/test/java/org/apache/camel/component/context/SpringDslContextComponentTest.java Mon Feb 28 19:20:56 2011 @@ -0,0 +1,67 @@ +/** + * + * 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.context; + +import org.apache.camel.EndpointInject; +import org.apache.camel.Exchange; +import org.apache.camel.Message; +import org.apache.camel.Produce; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.component.mock.MockEndpoint; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; + +import java.util.List; + +/** + * Test defining a context component using the Spring XML DSL + */ +@ContextConfiguration +public class SpringDslContextComponentTest extends AbstractJUnit4SpringContextTests { + private static final transient Logger LOG = LoggerFactory.getLogger(SpringDslContextComponentTest.class); + + @EndpointInject(uri = "tester:results") + private MockEndpoint resultEndpoint; + + @Produce(uri = "tester:start") + private ProducerTemplate template; + + @Test + public void testUsingContextComponent() throws Exception { + + Object accounts = applicationContext.getBean("accounts"); + System.out.println("Found accounts: " + accounts); + + resultEndpoint.expectedHeaderReceived("received", "true"); + resultEndpoint.expectedMessageCount(2); + + template.sendBody("<purchaseOrder>one</purchaseOrder>"); + template.sendBody("<purchaseOrder>two</purchaseOrder>"); + + resultEndpoint.assertIsSatisfied(); + + List<Exchange> receivedExchanges = resultEndpoint.getReceivedExchanges(); + for (Exchange exchange : receivedExchanges) { + Message in = exchange.getIn(); + LOG.info("Received from: " + exchange.getFromEndpoint() + " headers: " + in.getHeaders() + " body: " + in.getBody()); + } + } +} Added: camel/trunk/components/camel-context/src/test/resources/org/apache/camel/component/context/SpringDslContextComponentTest-context.xml URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-context/src/test/resources/org/apache/camel/component/context/SpringDslContextComponentTest-context.xml?rev=1075495&view=auto ============================================================================== --- camel/trunk/components/camel-context/src/test/resources/org/apache/camel/component/context/SpringDslContextComponentTest-context.xml (added) +++ camel/trunk/components/camel-context/src/test/resources/org/apache/camel/component/context/SpringDslContextComponentTest-context.xml Mon Feb 28 19:20:56 2011 @@ -0,0 +1,55 @@ +<?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 + "> + + <!-- the test case route --> + <camelContext id="tester" xmlns="http://camel.apache.org/schema/spring" depends-on="accounts"> + <route> + <from uri="direct:start"/> + <to uri="accounts:purchaseOrder"/> + </route> + <route> + <from uri="accounts:invoice"/> + <to uri="mock:results"/> + </route> + </camelContext> + + <!-- lets define a context component --> + <camelContext id="accounts" xmlns="http://camel.apache.org/schema/spring"> + <route> + <!-- + receive purchase orders, lets process it in some way then + send an invoice to our invoice endpoint + --> + <from uri="direct:purchaseOrder"/> + <setHeader headerName="received"> + <constant>true</constant> + </setHeader> + <to uri="direct:invoice"/> + </route> + </camelContext> + + + + +</beans> Modified: camel/trunk/components/camel-spring/src/main/java/org/apache/camel/spring/CamelBeanPostProcessor.java URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-spring/src/main/java/org/apache/camel/spring/CamelBeanPostProcessor.java?rev=1075495&r1=1075494&r2=1075495&view=diff ============================================================================== --- camel/trunk/components/camel-spring/src/main/java/org/apache/camel/spring/CamelBeanPostProcessor.java (original) +++ camel/trunk/components/camel-spring/src/main/java/org/apache/camel/spring/CamelBeanPostProcessor.java Mon Feb 28 19:20:56 2011 @@ -91,19 +91,16 @@ public class CamelBeanPostProcessor impl return bean; } - if (camelContext == null && applicationContext.containsBean(camelId)) { - setCamelContext((CamelContext) applicationContext.getBean(camelId)); - } - injectFields(bean, beanName); injectMethods(bean, beanName); if (bean instanceof CamelContextAware && canSetCamelContext(bean, beanName)) { CamelContextAware contextAware = (CamelContextAware)bean; - if (camelContext == null) { + CamelContext context = getOrLookupCamelContext(); + if (context == null) { LOG.warn("No CamelContext defined yet so cannot inject into bean: " + beanName); } else { - contextAware.setCamelContext(camelContext); + contextAware.setCamelContext(context); } } @@ -141,36 +138,6 @@ public class CamelBeanPostProcessor impl public void setCamelContext(CamelContext camelContext) { this.camelContext = camelContext; - postProcessor = new CamelPostProcessorHelper(camelContext) { - @Override - protected RuntimeException createProxyInstantiationRuntimeException(Class<?> type, Endpoint endpoint, Exception e) { - return new BeanInstantiationException(type, "Could not instantiate proxy of type " + type.getName() + " on endpoint " + endpoint, e); - } - - protected boolean isSingleton(Object bean, String beanName) { - // no application context has been injected which means the bean - // has not been enlisted in Spring application context - if (applicationContext == null || beanName == null) { - return super.isSingleton(bean, beanName); - } else { - return applicationContext.isSingleton(beanName); - } - } - - protected void startService(Service service, Object bean, String beanName) throws Exception { - if (isSingleton(bean, beanName)) { - getCamelContext().addService(service); - } else { - // only start service and do not add it to CamelContext - ServiceHelper.startService(service); - if (prototypeBeans.add(beanName)) { - // do not spam the log with WARN so do this only once per bean name - LOG.warn("The bean with id [" + beanName + "] is prototype scoped and cannot stop the injected service when bean is destroyed: " - + service + ". You may want to stop the service manually from the bean."); - } - } - } - }; } public String getCamelId() { @@ -228,12 +195,12 @@ public class CamelBeanPostProcessor impl ReflectionUtils.doWithFields(bean.getClass(), new ReflectionUtils.FieldCallback() { public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { EndpointInject endpointInject = field.getAnnotation(EndpointInject.class); - if (endpointInject != null && postProcessor.matchContext(endpointInject.context())) { + if (endpointInject != null && getPostProcessor().matchContext(endpointInject.context())) { injectField(field, endpointInject.uri(), endpointInject.ref(), bean, beanName); } Produce produce = field.getAnnotation(Produce.class); - if (produce != null && postProcessor.matchContext(produce.context())) { + if (produce != null && getPostProcessor().matchContext(produce.context())) { injectField(field, produce.uri(), produce.ref(), bean, beanName); } } @@ -255,12 +222,12 @@ public class CamelBeanPostProcessor impl protected void setterInjection(Method method, Object bean, String beanName) { EndpointInject endpointInject = method.getAnnotation(EndpointInject.class); - if (endpointInject != null && postProcessor.matchContext(endpointInject.context())) { + if (endpointInject != null && getPostProcessor().matchContext(endpointInject.context())) { setterInjection(method, bean, beanName, endpointInject.uri(), endpointInject.ref()); } Produce produce = method.getAnnotation(Produce.class); - if (produce != null && postProcessor.matchContext(produce.context())) { + if (produce != null && getPostProcessor().matchContext(produce.context())) { setterInjection(method, bean, beanName, produce.uri(), produce.ref()); } } @@ -278,8 +245,57 @@ public class CamelBeanPostProcessor impl } } + protected CamelContext getOrLookupCamelContext() { + if (camelContext == null && applicationContext.containsBean(camelId)) { + camelContext = (CamelContext) applicationContext.getBean(camelId); + } + return camelContext; + } + public CamelPostProcessorHelper getPostProcessor() { - ObjectHelper.notNull(postProcessor, "postProcessor"); + // lets lazily create the post processor + if (postProcessor == null) { + postProcessor = new CamelPostProcessorHelper() { + + @Override + public CamelContext getCamelContext() { + // lets lazily lookup the camel context here + // as doing this will cause this context to be started immediately + // breaking the lifecycle ordering of different camel contexts + // so we only want to do this on demand + return getOrLookupCamelContext(); + } + + @Override + protected RuntimeException createProxyInstantiationRuntimeException(Class<?> type, Endpoint endpoint, Exception e) { + return new BeanInstantiationException(type, "Could not instantiate proxy of type " + type.getName() + " on endpoint " + endpoint, e); + } + + protected boolean isSingleton(Object bean, String beanName) { + // no application context has been injected which means the bean + // has not been enlisted in Spring application context + if (applicationContext == null || beanName == null) { + return super.isSingleton(bean, beanName); + } else { + return applicationContext.isSingleton(beanName); + } + } + + protected void startService(Service service, Object bean, String beanName) throws Exception { + if (isSingleton(bean, beanName)) { + getCamelContext().addService(service); + } else { + // only start service and do not add it to CamelContext + ServiceHelper.startService(service); + if (prototypeBeans.add(beanName)) { + // do not spam the log with WARN so do this only once per bean name + LOG.warn("The bean with id [" + beanName + "] is prototype scoped and cannot stop the injected service when bean is destroyed: " + + service + ". You may want to stop the service manually from the bean."); + } + } + } + }; + } return postProcessor; }