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