Coverage Report - org.apache.camel.spring.CamelBeanPostProcessor
 
Classes in this File Line Coverage Branch Coverage Complexity
CamelBeanPostProcessor
81% 
100% 
0
 
 1  
 /**
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.apache.camel.spring;
 18  
 
 19  
 import java.lang.reflect.Field;
 20  
 import java.lang.reflect.Method;
 21  
 
 22  
 import javax.xml.bind.annotation.XmlAccessType;
 23  
 import javax.xml.bind.annotation.XmlAccessorType;
 24  
 import javax.xml.bind.annotation.XmlRootElement;
 25  
 import javax.xml.bind.annotation.XmlTransient;
 26  
 
 27  
 import org.apache.camel.CamelContextAware;
 28  
 import org.apache.camel.CamelTemplate;
 29  
 import org.apache.camel.Consumer;
 30  
 import org.apache.camel.Endpoint;
 31  
 import org.apache.camel.EndpointInject;
 32  
 import org.apache.camel.MessageDriven;
 33  
 import org.apache.camel.Processor;
 34  
 import org.apache.camel.Producer;
 35  
 import org.apache.camel.RuntimeCamelException;
 36  
 import org.apache.camel.component.bean.BeanProcessor;
 37  
 import org.apache.camel.spring.util.ReflectionUtils;
 38  
 import org.apache.camel.util.ObjectHelper;
 39  
 import org.apache.commons.logging.Log;
 40  
 import org.apache.commons.logging.LogFactory;
 41  
 
 42  
 import org.springframework.beans.BeansException;
 43  
 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
 44  
 import org.springframework.beans.factory.config.BeanPostProcessor;
 45  
 import org.springframework.context.ApplicationContext;
 46  
 import org.springframework.context.ApplicationContextAware;
 47  
 
 48  
 import static org.apache.camel.util.ObjectHelper.isNotNullAndNonEmpty;
 49  
 
 50  
 /**
 51  
  * A post processor to perform injection of {@link Endpoint} and
 52  
  * {@link Producer} instances together with binding methods annotated with
 53  
  * {@link @MessageDriven} to a Camel consumer.
 54  
  * 
 55  
  * @version $Revision: 1.1 $
 56  
  */
 57  
 @XmlRootElement(name = "beanPostProcessor")
 58  
 @XmlAccessorType(XmlAccessType.FIELD)
 59  
 public class CamelBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
 60  1
     private static final transient Log LOG = LogFactory.getLog(CamelBeanPostProcessor.class);
 61  
     @XmlTransient
 62  
     private SpringCamelContext camelContext;
 63  
     @XmlTransient
 64  
     private ApplicationContext applicationContext;
 65  
 
 66  
     // private List<Consumer> consumers = new ArrayList<Consumer>();
 67  
 
 68  61
     public CamelBeanPostProcessor() {
 69  61
     }
 70  
 
 71  
     public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
 72  82
         injectFields(bean);
 73  82
         injectMethods(bean);
 74  82
         if (bean instanceof CamelContextAware) {
 75  6
             CamelContextAware contextAware = (CamelContextAware)bean;
 76  6
             if (camelContext == null) {
 77  0
                 LOG.warn("No CamelContext defined yet so cannot inject into: " + bean);
 78  0
             } else {
 79  6
                 contextAware.setCamelContext(camelContext);
 80  
             }
 81  
         }
 82  82
         return bean;
 83  
     }
 84  
 
 85  
     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
 86  103
         return bean;
 87  
     }
 88  
 
 89  
     // Properties
 90  
     // -------------------------------------------------------------------------
 91  
 
 92  
     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
 93  53
         this.applicationContext = applicationContext;
 94  53
     }
 95  
 
 96  
     public SpringCamelContext getCamelContext() {
 97  8
         return camelContext;
 98  
     }
 99  
 
 100  
     public void setCamelContext(SpringCamelContext camelContext) {
 101  53
         this.camelContext = camelContext;
 102  53
     }
 103  
 
 104  
     // Implementation methods
 105  
     // -------------------------------------------------------------------------
 106  
 
 107  
     /**
 108  
      * A strategy method to allow implementations to perform some custom JBI
 109  
      * based injection of the POJO
 110  
      * 
 111  
      * @param bean the bean to be injected
 112  
      */
 113  
     protected void injectFields(final Object bean) {
 114  82
         ReflectionUtils.doWithFields(bean.getClass(), new ReflectionUtils.FieldCallback() {
 115  82
             public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
 116  501
                 EndpointInject annotation = field.getAnnotation(EndpointInject.class);
 117  501
                 if (annotation != null) {
 118  8
                     ReflectionUtils.setField(field, bean, getEndpointInjectionValue(annotation, field.getType()));
 119  
                 }
 120  501
             }
 121  
         });
 122  82
     }
 123  
 
 124  
     protected void injectMethods(final Object bean) {
 125  82
         ReflectionUtils.doWithMethods(bean.getClass(), new ReflectionUtils.MethodCallback() {
 126  
             @SuppressWarnings("unchecked")
 127  82
             public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
 128  2783
                 setterInjection(method, bean);
 129  2783
                 consumerInjection(method, bean);
 130  2783
             }
 131  
         });
 132  82
     }
 133  
 
 134  
     protected void setterInjection(Method method, Object bean) {
 135  2783
         EndpointInject annoation = method.getAnnotation(EndpointInject.class);
 136  2783
         if (annoation != null) {
 137  3
             Class<?>[] parameterTypes = method.getParameterTypes();
 138  3
             if (parameterTypes != null) {
 139  3
                 if (parameterTypes.length != 1) {
 140  0
                     LOG.warn("Ignoring badly annotated method for injection due to incorrect number of parameters: " + method);
 141  0
                 } else {
 142  3
                     Object value = getEndpointInjectionValue(annoation, parameterTypes[0]);
 143  3
                     ObjectHelper.invokeMethod(method, bean, value);
 144  
                 }
 145  
             }
 146  
         }
 147  2783
     }
 148  
 
 149  
     protected void consumerInjection(final Object bean) {
 150  0
         ReflectionUtils.doWithMethods(bean.getClass(), new ReflectionUtils.MethodCallback() {
 151  
             @SuppressWarnings("unchecked")
 152  0
             public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
 153  
                 /*
 154  
                  * TODO support callbacks? if
 155  
                  * (method.getAnnotation(Callback.class) != null) { try {
 156  
                  * Expression e = ExpressionFactory.createExpression(
 157  
                  * method.getAnnotation(Callback.class).condition());
 158  
                  * JexlContext jc = JexlHelper.createContext();
 159  
                  * jc.getVars().put("this", obj); Object r = e.evaluate(jc); if
 160  
                  * (!(r instanceof Boolean)) { throw new
 161  
                  * RuntimeException("Expression did not returned a boolean value
 162  
                  * but: " + r); } Boolean oldVal =
 163  
                  * req.getCallbacks().get(method); Boolean newVal = (Boolean) r;
 164  
                  * if ((oldVal == null || !oldVal) && newVal) {
 165  
                  * req.getCallbacks().put(method, newVal); method.invoke(obj,
 166  
                  * new Object[0]); // TODO: handle return value and sent it as
 167  
                  * the answer } } catch (Exception e) { throw new
 168  
                  * RuntimeException("Unable to invoke callback", e); } }
 169  
                  */
 170  0
             }
 171  
         });
 172  0
     }
 173  
 
 174  
     protected void consumerInjection(Method method, Object bean) {
 175  2783
         MessageDriven annotation = method.getAnnotation(MessageDriven.class);
 176  2783
         if (annotation != null) {
 177  1
             LOG.info("Creating a consumer for: " + annotation);
 178  
 
 179  
             // lets bind this method to a listener
 180  1
             Endpoint endpoint = getEndpointInjection(annotation.uri(), annotation.name());
 181  1
             if (endpoint != null) {
 182  
                 try {
 183  1
                     Processor processor = createConsumerProcessor(bean, method, endpoint);
 184  1
                     LOG.info("Created processor: " + processor);
 185  1
                     Consumer consumer = endpoint.createConsumer(processor);
 186  1
                     consumer.start();
 187  1
                     addConsumer(consumer);
 188  0
                 } catch (Exception e) {
 189  0
                     LOG.warn(e);
 190  0
                     throw new RuntimeCamelException(e);
 191  1
                 }
 192  
             }
 193  
         }
 194  2783
     }
 195  
 
 196  
     /**
 197  
      * Create a processor which invokes the given method when an incoming
 198  
      * message exchange is received
 199  
      */
 200  
     protected Processor createConsumerProcessor(final Object pojo, final Method method, final Endpoint endpoint) {
 201  1
         BeanProcessor answer = new BeanProcessor(pojo, getCamelContext());
 202  1
         answer.setMethod(method);
 203  1
         return answer;
 204  
     }
 205  
 
 206  
     protected void addConsumer(Consumer consumer) {
 207  1
         LOG.debug("Adding consumer: " + consumer);
 208  
         // consumers.add(consumer);
 209  1
     }
 210  
 
 211  
     /**
 212  
      * Creates the value for the injection point for the given annotation
 213  
      */
 214  
     protected Object getEndpointInjectionValue(EndpointInject annotation, Class<?> type) {
 215  11
         Endpoint endpoint = getEndpointInjection(annotation.uri(), annotation.name());
 216  11
         if (endpoint != null) {
 217  11
             if (type.isInstance(endpoint)) {
 218  2
                 return endpoint;
 219  9
             } else if (type.isAssignableFrom(Producer.class)) {
 220  
                 try {
 221  2
                     return endpoint.createProducer();
 222  0
                 } catch (Exception e) {
 223  0
                     throw new RuntimeCamelException(e);
 224  
                 }
 225  7
             } else if (type.isAssignableFrom(CamelTemplate.class)) {
 226  7
                 return new CamelTemplate(getCamelContext(), endpoint);
 227  
             }
 228  
         }
 229  0
         return null;
 230  
     }
 231  
 
 232  
     protected Endpoint getEndpointInjection(String uri, String name) {
 233  12
         Endpoint endpoint = null;
 234  12
         if (isNotNullAndNonEmpty(uri)) {
 235  11
             endpoint = camelContext.getEndpoint(uri);
 236  11
         } else {
 237  1
             if (isNotNullAndNonEmpty(name)) {
 238  1
                 endpoint = (Endpoint)applicationContext.getBean(name);
 239  1
                 if (endpoint == null) {
 240  0
                     throw new NoSuchBeanDefinitionException(name);
 241  
                 }
 242  
             } else {
 243  0
                 LOG.warn("No uri or name specified on @EndpointInject annotation!");
 244  
             }
 245  
         }
 246  12
         return endpoint;
 247  
     }
 248  
 
 249  
 }