001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.spring; 018 019import java.util.Map; 020import java.util.Set; 021import javax.xml.bind.annotation.XmlAccessType; 022import javax.xml.bind.annotation.XmlAccessorType; 023import javax.xml.bind.annotation.XmlRootElement; 024import javax.xml.bind.annotation.XmlTransient; 025 026import org.apache.camel.CamelContext; 027import org.apache.camel.Endpoint; 028import org.apache.camel.core.xml.CamelJMXAgentDefinition; 029import org.apache.camel.impl.CamelPostProcessorHelper; 030import org.apache.camel.impl.DefaultCamelBeanPostProcessor; 031import org.apache.camel.spi.Metadata; 032import org.slf4j.Logger; 033import org.slf4j.LoggerFactory; 034import org.springframework.beans.BeanInstantiationException; 035import org.springframework.beans.BeansException; 036import org.springframework.beans.factory.config.BeanPostProcessor; 037import org.springframework.context.ApplicationContext; 038import org.springframework.context.ApplicationContextAware; 039 040/** 041 * Spring specific {@link DefaultCamelBeanPostProcessor} which uses Spring {@link BeanPostProcessor} to post process beans. 042 * 043 * @see DefaultCamelBeanPostProcessor 044 */ 045@Metadata(label = "spring,configuration") 046@XmlRootElement(name = "beanPostProcessor") 047@XmlAccessorType(XmlAccessType.FIELD) 048public class CamelBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware { 049 private static final Logger LOG = LoggerFactory.getLogger(CamelBeanPostProcessor.class); 050 @XmlTransient 051 private CamelContext camelContext; 052 @XmlTransient 053 private ApplicationContext applicationContext; 054 @XmlTransient 055 private String camelId; 056 057 // must use a delegate, as we cannot extend DefaultCamelBeanPostProcessor, as this will cause the 058 // XSD schema generator to include the DefaultCamelBeanPostProcessor as a type, which we do not want to 059 @XmlTransient 060 private final DefaultCamelBeanPostProcessor delegate = new DefaultCamelBeanPostProcessor() { 061 @Override 062 public CamelContext getOrLookupCamelContext() { 063 if (camelContext == null) { 064 if (camelId != null) { 065 LOG.trace("Looking up CamelContext by id: {} from Spring ApplicationContext: {}", camelId, applicationContext); 066 camelContext = applicationContext.getBean(camelId, CamelContext.class); 067 } else { 068 // lookup by type and grab the single CamelContext if exists 069 LOG.trace("Looking up CamelContext by type from Spring ApplicationContext: {}", applicationContext); 070 Map<String, CamelContext> contexts = applicationContext.getBeansOfType(CamelContext.class); 071 if (contexts != null && contexts.size() == 1) { 072 camelContext = contexts.values().iterator().next(); 073 } 074 } 075 } 076 return camelContext; 077 } 078 079 @Override 080 public boolean canPostProcessBean(Object bean, String beanName) { 081 // the JMXAgent is a bit strange and causes Spring issues if we let it being 082 // post processed by this one. It does not need it anyway so we are good to go. 083 // We should also avoid to process the null object bean (in Spring 2.5.x) 084 if (bean == null || bean instanceof CamelJMXAgentDefinition) { 085 return false; 086 } 087 088 return super.canPostProcessBean(bean, beanName); 089 } 090 091 @Override 092 public CamelPostProcessorHelper getPostProcessorHelper() { 093 // lets lazily create the post processor 094 if (camelPostProcessorHelper == null) { 095 camelPostProcessorHelper = new CamelPostProcessorHelper() { 096 097 @Override 098 public CamelContext getCamelContext() { 099 // lets lazily lookup the camel context here 100 // as doing this will cause this context to be started immediately 101 // breaking the lifecycle ordering of different camel contexts 102 // so we only want to do this on demand 103 return delegate.getOrLookupCamelContext(); 104 } 105 106 @Override 107 protected RuntimeException createProxyInstantiationRuntimeException(Class<?> type, Endpoint endpoint, Exception e) { 108 return new BeanInstantiationException(type, "Could not instantiate proxy of type " + type.getName() + " on endpoint " + endpoint, e); 109 } 110 111 protected boolean isSingleton(Object bean, String beanName) { 112 // no application context has been injected which means the bean 113 // has not been enlisted in Spring application context 114 if (applicationContext == null || beanName == null) { 115 return super.isSingleton(bean, beanName); 116 } else { 117 return applicationContext.isSingleton(beanName); 118 } 119 } 120 }; 121 } 122 return camelPostProcessorHelper; 123 } 124 }; 125 126 public CamelBeanPostProcessor() { 127 } 128 129 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 130 try { 131 return delegate.postProcessBeforeInitialization(bean, beanName); 132 } catch (Exception e) { 133 // do not wrap already beans exceptions 134 if (e instanceof BeansException) { 135 throw (BeansException) e; 136 } 137 throw new GenericBeansException("Error post processing bean: " + beanName, e); 138 } 139 } 140 141 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 142 try { 143 return delegate.postProcessAfterInitialization(bean, beanName); 144 } catch (Exception e) { 145 // do not wrap already beans exceptions 146 if (e instanceof BeansException) { 147 throw (BeansException) e; 148 } 149 throw new GenericBeansException("Error post processing bean: " + beanName, e); 150 } 151 } 152 153 // Properties 154 // ------------------------------------------------------------------------- 155 156 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 157 this.applicationContext = applicationContext; 158 } 159 160 public CamelContext getCamelContext() { 161 return camelContext; 162 } 163 164 public void setCamelContext(CamelContext camelContext) { 165 this.camelContext = camelContext; 166 } 167 168 public String getCamelId() { 169 return camelId; 170 } 171 172 public void setCamelId(String camelId) { 173 this.camelId = camelId; 174 } 175 176}