| /** |
| * 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; |
| |
| import org.apache.camel.Endpoint; |
| import org.apache.camel.component.bean.BeanProcessor; |
| import org.apache.camel.component.event.EventComponent; |
| import org.apache.camel.component.event.EventEndpoint; |
| import org.apache.camel.impl.DefaultCamelContext; |
| import org.apache.camel.impl.ProcessorEndpoint; |
| import org.apache.camel.spi.Injector; |
| import org.apache.camel.spi.Registry; |
| import org.apache.camel.spring.spi.ApplicationContextRegistry; |
| import org.apache.camel.spring.spi.SpringInjector; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| import org.springframework.beans.BeansException; |
| import org.springframework.beans.factory.DisposableBean; |
| import org.springframework.beans.factory.InitializingBean; |
| import org.springframework.context.ApplicationContext; |
| import org.springframework.context.ApplicationContextAware; |
| import org.springframework.context.ApplicationEvent; |
| import org.springframework.context.ConfigurableApplicationContext; |
| import org.springframework.context.event.ContextRefreshedEvent; |
| import org.springframework.context.event.ContextStoppedEvent; |
| import org.springframework.context.support.ClassPathXmlApplicationContext; |
| |
| import static org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException; |
| |
| /** |
| * A Spring aware implementation of {@link org.apache.camel.CamelContext} which |
| * will automatically register itself with Springs lifecycle methods plus allows |
| * spring to be used to customize a any <a |
| * href="http://camel.apache.org/type-converter.html">Type Converters</a> |
| * as well as supporting accessing components and beans via the Spring |
| * {@link ApplicationContext} |
| * |
| * @version |
| */ |
| public class SpringCamelContext extends DefaultCamelContext implements InitializingBean, DisposableBean, |
| ApplicationContextAware { |
| |
| private static final transient Logger LOG = LoggerFactory.getLogger(SpringCamelContext.class); |
| private static final ThreadLocal<Boolean> NO_START = new ThreadLocal<Boolean>(); |
| private ApplicationContext applicationContext; |
| private EventEndpoint eventEndpoint; |
| |
| public SpringCamelContext() { |
| } |
| |
| public SpringCamelContext(ApplicationContext applicationContext) { |
| setApplicationContext(applicationContext); |
| } |
| |
| |
| public static void setNoStart(boolean b) { |
| if (b) { |
| NO_START.set(b); |
| } else { |
| NO_START.remove(); |
| } |
| } |
| |
| public static SpringCamelContext springCamelContext(ApplicationContext applicationContext) throws Exception { |
| return springCamelContext(applicationContext, true); |
| } |
| |
| public static SpringCamelContext springCamelContext(ApplicationContext applicationContext, boolean maybeStart) throws Exception { |
| // lets try and look up a configured camel context in the context |
| String[] names = applicationContext.getBeanNamesForType(SpringCamelContext.class); |
| if (names.length == 1) { |
| return (SpringCamelContext)applicationContext.getBean(names[0], SpringCamelContext.class); |
| } |
| SpringCamelContext answer = new SpringCamelContext(); |
| answer.setApplicationContext(applicationContext); |
| if (maybeStart) { |
| answer.afterPropertiesSet(); |
| } |
| return answer; |
| } |
| |
| public static SpringCamelContext springCamelContext(String configLocations) throws Exception { |
| return springCamelContext(new ClassPathXmlApplicationContext(configLocations)); |
| } |
| |
| public void afterPropertiesSet() throws Exception { |
| maybeStart(); |
| } |
| |
| public void destroy() throws Exception { |
| stop(); |
| } |
| |
| public void onApplicationEvent(ApplicationEvent event) { |
| LOG.debug("onApplicationEvent: {}", event); |
| |
| if (event instanceof ContextRefreshedEvent) { |
| // now lets start the CamelContext so that all its possible |
| // dependencies are initialized |
| try { |
| maybeStart(); |
| } catch (Exception e) { |
| throw wrapRuntimeCamelException(e); |
| } |
| } else if (event instanceof ContextStoppedEvent) { |
| try { |
| maybeStop(); |
| } catch (Exception e) { |
| throw wrapRuntimeCamelException(e); |
| } |
| } |
| |
| if (eventEndpoint != null) { |
| eventEndpoint.onApplicationEvent(event); |
| } else { |
| LOG.info("No spring-event endpoint enabled to handle event: {}", event); |
| } |
| } |
| |
| // Properties |
| // ----------------------------------------------------------------------- |
| |
| public ApplicationContext getApplicationContext() { |
| return applicationContext; |
| } |
| |
| public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { |
| this.applicationContext = applicationContext; |
| ClassLoader cl; |
| |
| // set the application context classloader |
| if (applicationContext != null && applicationContext.getClassLoader() != null) { |
| cl = applicationContext.getClassLoader(); |
| } else { |
| LOG.warn("Cannot find the class loader from application context, using the thread context class loader instead"); |
| cl = Thread.currentThread().getContextClassLoader(); |
| } |
| LOG.debug("Set the application context classloader to: {}", cl); |
| this.setApplicationContextClassLoader(cl); |
| |
| if (applicationContext instanceof ConfigurableApplicationContext) { |
| // only add if not already added |
| if (hasComponent("spring-event") == null) { |
| addComponent("spring-event", new EventComponent(applicationContext)); |
| } |
| } |
| } |
| |
| public EventEndpoint getEventEndpoint() { |
| return eventEndpoint; |
| } |
| |
| public void setEventEndpoint(EventEndpoint eventEndpoint) { |
| this.eventEndpoint = eventEndpoint; |
| } |
| |
| // Implementation methods |
| // ----------------------------------------------------------------------- |
| |
| @Override |
| protected void doStart() throws Exception { |
| super.doStart(); |
| if (eventEndpoint == null) { |
| eventEndpoint = createEventEndpoint(); |
| } |
| } |
| |
| @Override |
| protected Injector createInjector() { |
| if (applicationContext instanceof ConfigurableApplicationContext) { |
| return new SpringInjector((ConfigurableApplicationContext)applicationContext); |
| } else { |
| LOG.warn("Cannot use SpringInjector as applicationContext is not a ConfigurableApplicationContext as its: " |
| + applicationContext); |
| return super.createInjector(); |
| } |
| } |
| |
| protected EventEndpoint createEventEndpoint() { |
| return getEndpoint("spring-event:default", EventEndpoint.class); |
| } |
| |
| protected Endpoint convertBeanToEndpoint(String uri, Object bean) { |
| // We will use the type convert to build the endpoint first |
| Endpoint endpoint = getTypeConverter().convertTo(Endpoint.class, bean); |
| if (endpoint != null) { |
| endpoint.setCamelContext(this); |
| return endpoint; |
| } |
| |
| return new ProcessorEndpoint(uri, this, new BeanProcessor(bean, this)); |
| } |
| |
| @Override |
| protected Registry createRegistry() { |
| return new ApplicationContextRegistry(getApplicationContext()); |
| } |
| |
| private void maybeStart() throws Exception { |
| // for example from unit testing we want to start Camel later and not when Spring framework |
| // publish a ContextRefreshedEvent |
| String maybeStart = System.getProperty("maybeStartCamelContext", "true"); |
| |
| if ("true".equals(maybeStart) |
| && NO_START.get() == null) { |
| if (!isStarted() && !isStarting()) { |
| start(); |
| } else { |
| // ignore as Camel is already started |
| LOG.trace("Ignoring maybeStart() as Apache Camel is already started"); |
| } |
| } else { |
| LOG.trace("Ignoring maybeStart() as System property maybeStartCamelContext is false"); |
| } |
| } |
| |
| private void maybeStop() throws Exception { |
| if (!isStopping() && !isStopped()) { |
| stop(); |
| } else { |
| // ignore as Camel is already stopped |
| LOG.trace("Ignoring maybeStop() as Apache Camel is already stopped"); |
| } |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("SpringCamelContext(").append(getName()).append(")"); |
| if (applicationContext != null) { |
| sb.append(" with spring id ").append(applicationContext.getId()); |
| } |
| return sb.toString(); |
| } |
| |
| } |