Guest User

BeanInfo-Cache.patch

a guest
Feb 5th, 2013
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 17.72 KB | None | 0 0
  1. Index: src/main/java/org/apache/camel/component/bean/BeanInfo.java
  2. ===================================================================
  3. --- src/main/java/org/apache/camel/component/bean/BeanInfo.java (revision 1442130)
  4. +++ src/main/java/org/apache/camel/component/bean/BeanInfo.java (working copy)
  5. @@ -20,16 +20,7 @@
  6.  import java.lang.reflect.Method;
  7.  import java.lang.reflect.Modifier;
  8.  import java.lang.reflect.Proxy;
  9. -import java.util.ArrayList;
  10. -import java.util.Arrays;
  11. -import java.util.Collection;
  12. -import java.util.Collections;
  13. -import java.util.Comparator;
  14. -import java.util.HashMap;
  15. -import java.util.Iterator;
  16. -import java.util.List;
  17. -import java.util.Map;
  18. -
  19. +import java.util.*;
  20.  import org.apache.camel.Attachments;
  21.  import org.apache.camel.Body;
  22.  import org.apache.camel.CamelContext;
  23. @@ -55,10 +46,10 @@
  24.  /**
  25.   * Represents the metadata about a bean type created via a combination of
  26.   * introspection and annotations together with some useful sensible defaults
  27. - *
  28. - * @version
  29.   */
  30.  public class BeanInfo {
  31. +    public static final String BEAN_INFO_CACHE_REGISTRY_KEY = "CamelBeanInfoCache";
  32. +
  33.      private static final transient Logger LOG = LoggerFactory.getLogger(BeanInfo.class);
  34.      private static final String CGLIB_CLASS_SEPARATOR = "$$";
  35.      private static final List<Method> EXCLUDED_METHODS = new ArrayList<Method>();
  36. @@ -105,6 +96,22 @@
  37.          this.type = type;
  38.          this.strategy = strategy;
  39.  
  40. +        Map<CacheKey, BeanInfo> cache = (Map<CacheKey, BeanInfo>) camelContext.getRegistry().lookup(BEAN_INFO_CACHE_REGISTRY_KEY, Map.class);
  41. +        CacheKey cacheKey = new CacheKey(type, explicitMethod, strategy);
  42. +        if (cache != null) {
  43. +            BeanInfo beanInfo = cache.get(cacheKey);
  44. +            if (beanInfo != null) {
  45. +                defaultMethod = beanInfo.defaultMethod;
  46. +                operations = beanInfo.operations;
  47. +                operationsWithBody = beanInfo.operationsWithBody;
  48. +                operationsWithNoBody = beanInfo.operationsWithNoBody;
  49. +                operationsWithCustomAnnotation = beanInfo.operationsWithCustomAnnotation;
  50. +                operationsWithHandlerAnnotation = beanInfo.operationsWithHandlerAnnotation;
  51. +                methodMap = beanInfo.methodMap;
  52. +                return;
  53. +            }
  54. +        }
  55. +
  56.          if (explicitMethod != null) {
  57.              // must be a valid method
  58.              if (!isValidMethod(type, explicitMethod)) {
  59. @@ -133,6 +140,10 @@
  60.          operationsWithCustomAnnotation = Collections.unmodifiableList(operationsWithCustomAnnotation);
  61.          operationsWithHandlerAnnotation = Collections.unmodifiableList(operationsWithHandlerAnnotation);
  62.          methodMap = Collections.unmodifiableMap(methodMap);
  63. +
  64. +        if (cache != null) {
  65. +            cache.put(cacheKey, this);
  66. +        }
  67.      }
  68.  
  69.      public Class<?> getType() {
  70. @@ -155,15 +166,14 @@
  71.          return answer;
  72.      }
  73.  
  74. -    public MethodInvocation createInvocation(Object pojo, Exchange exchange)
  75. -        throws AmbiguousMethodCallException, MethodNotFoundException {
  76. +    public MethodInvocation createInvocation(Object pojo, Exchange exchange) throws AmbiguousMethodCallException, MethodNotFoundException {
  77.          return createInvocation(pojo, exchange, null);
  78.      }
  79.  
  80.      private MethodInvocation createInvocation(Object pojo, Exchange exchange, Method explicitMethod)
  81. -        throws AmbiguousMethodCallException, MethodNotFoundException {
  82. +            throws AmbiguousMethodCallException, MethodNotFoundException {
  83.          MethodInfo methodInfo = null;
  84. -        
  85. +
  86.          // find the explicit method to invoke
  87.          if (explicitMethod != null) {
  88.              Iterator<List<MethodInfo>> it = operations.values().iterator();
  89. @@ -192,7 +202,8 @@
  90.              if ("class".equals(name) || "getClass".equals(name)) {
  91.                  try {
  92.                      Method method = pojo.getClass().getMethod("getClass");
  93. -                    methodInfo = new MethodInfo(exchange.getContext(), pojo.getClass(), method, Collections.<ParameterInfo>emptyList(), Collections.<ParameterInfo>emptyList(), false, false);
  94. +                    methodInfo = new MethodInfo(exchange.getContext(), pojo.getClass(), method, Collections.<ParameterInfo>emptyList(),
  95. +                                                Collections.<ParameterInfo>emptyList(), false, false);
  96.                  } catch (NoSuchMethodException e) {
  97.                      throw new MethodNotFoundException(exchange, pojo, "getClass");
  98.                  }
  99. @@ -252,12 +263,12 @@
  100.          if (!Modifier.isPublic(clazz.getModifiers())) {
  101.              LOG.trace("Preferring interface methods as class: {} is not public accessible", clazz);
  102.              List<Method> interfaceMethods = getInterfaceMethods(clazz);
  103. -            
  104. +
  105.              // still keep non-accessible class methods to provide more specific Exception if method is non-accessible
  106.              interfaceMethods.addAll(methods);
  107.              methods = interfaceMethods;
  108.          }
  109. -        
  110. +
  111.          for (Method method : methods) {
  112.              boolean valid = isValidMethod(clazz, method);
  113.              LOG.trace("Method: {} is valid: {}", method, valid);
  114. @@ -325,7 +336,6 @@
  115.          return methodInfo;
  116.      }
  117.  
  118. -
  119.      /**
  120.       * Returns the {@link MethodInfo} for the given method if it exists or null
  121.       * if there is no metadata available for the given method
  122. @@ -399,8 +409,7 @@
  123.      }
  124.  
  125.      protected List<Annotation>[] collectParameterAnnotations(Class<?> c, Method m) {
  126. -        @SuppressWarnings("unchecked")
  127. -        List<Annotation>[] annotations = new List[m.getParameterTypes().length];
  128. +        @SuppressWarnings("unchecked") List<Annotation>[] annotations = new List[m.getParameterTypes().length];
  129.          for (int i = 0; i < annotations.length; i++) {
  130.              annotations[i] = new ArrayList<Annotation>();
  131.          }
  132. @@ -490,7 +499,7 @@
  133.          possibleOperations.addAll(localOperationsWithCustomAnnotation);
  134.  
  135.          if (!possibleOperations.isEmpty()) {
  136. -             // multiple possible operations so find the best suited if possible
  137. +            // multiple possible operations so find the best suited if possible
  138.              MethodInfo answer = chooseMethodWithMatchingBody(exchange, possibleOperations, localOperationsWithCustomAnnotation);
  139.              if (answer == null) {
  140.                  throw new AmbiguousMethodCallException(exchange, possibleOperations);
  141. @@ -502,10 +511,9 @@
  142.          // not possible to determine
  143.          return null;
  144.      }
  145. -    
  146. -    private MethodInfo chooseMethodWithMatchingBody(Exchange exchange, Collection<MethodInfo> operationList,
  147. -                                                    List<MethodInfo> operationsWithCustomAnnotation)
  148. -        throws AmbiguousMethodCallException {
  149. +
  150. +    private MethodInfo chooseMethodWithMatchingBody(Exchange exchange, Collection<MethodInfo> operationList, List<MethodInfo> operationsWithCustomAnnotation)
  151. +            throws AmbiguousMethodCallException {
  152.          // see if we can find a method whose body param type matches the message body
  153.          Message in = exchange.getIn();
  154.          Object body = in.getBody();
  155. @@ -546,10 +554,9 @@
  156.          return null;
  157.      }
  158.  
  159. -    private MethodInfo chooseBestPossibleMethodInfo(Exchange exchange, Collection<MethodInfo> operationList, Object body,
  160. -                                                    List<MethodInfo> possibles, List<MethodInfo> possiblesWithException,
  161. -                                                    List<MethodInfo> possibleWithCustomAnnotation)
  162. -        throws AmbiguousMethodCallException {
  163. +    private MethodInfo chooseBestPossibleMethodInfo(Exchange exchange, Collection<MethodInfo> operationList, Object body, List<MethodInfo> possibles,
  164. +                                                    List<MethodInfo> possiblesWithException, List<MethodInfo> possibleWithCustomAnnotation)
  165. +            throws AmbiguousMethodCallException {
  166.  
  167.          Exception exception = ExpressionBuilder.exchangeExceptionExpression().evaluate(exchange, Exception.class);
  168.          if (exception != null && possiblesWithException.size() == 1) {
  169. @@ -574,8 +581,7 @@
  170.                  Object value = exchange.getContext().getTypeConverter().tryConvertTo(methodInfo.getBodyParameterType(), exchange, body);
  171.                  if (value != null) {
  172.                      if (LOG.isTraceEnabled()) {
  173. -                        LOG.trace("Converted body from: {} to: {}",
  174. -                                body.getClass().getCanonicalName(), methodInfo.getBodyParameterType().getCanonicalName());
  175. +                        LOG.trace("Converted body from: {} to: {}", body.getClass().getCanonicalName(), methodInfo.getBodyParameterType().getCanonicalName());
  176.                      }
  177.                      matchCounter++;
  178.                      newBody = value;
  179. @@ -609,8 +615,8 @@
  180.      /**
  181.       * Validates whether the given method is a valid candidate for Camel Bean Binding.
  182.       *
  183. -     * @param clazz   the class
  184. -     * @param method  the method
  185. +     * @param clazz the class
  186. +     * @param method the method
  187.       * @return true if valid, false to skip the method
  188.       */
  189.      protected boolean isValidMethod(Class<?> clazz, Method method) {
  190. @@ -638,7 +644,7 @@
  191.      /**
  192.       * Does the given method info override an existing method registered before (from a subclass)
  193.       *
  194. -     * @param methodInfo  the method to test
  195. +     * @param methodInfo the method to test
  196.       * @return the already registered method to use, null if not overriding any
  197.       */
  198.      private MethodInfo overridesExistingMethod(MethodInfo methodInfo) {
  199. @@ -656,8 +662,7 @@
  200.          return null;
  201.      }
  202.  
  203. -    private MethodInfo chooseMethodWithCustomAnnotations(Exchange exchange, Collection<MethodInfo> possibles)
  204. -        throws AmbiguousMethodCallException {
  205. +    private MethodInfo chooseMethodWithCustomAnnotations(Exchange exchange, Collection<MethodInfo> possibles) throws AmbiguousMethodCallException {
  206.          // if we have only one method with custom annotations let's choose that
  207.          MethodInfo chosen = null;
  208.          for (MethodInfo possible : possibles) {
  209. @@ -682,8 +687,7 @@
  210.       * insufficient annotations or not fitting with the default type
  211.       * conventions.
  212.       */
  213. -    private Expression createParameterUnmarshalExpression(Class<?> clazz, Method method,
  214. -            Class<?> parameterType, Annotation[] parameterAnnotation) {
  215. +    private Expression createParameterUnmarshalExpression(Class<?> clazz, Method method, Class<?> parameterType, Annotation[] parameterAnnotation) {
  216.  
  217.          // look for a parameter annotation that converts into an expression
  218.          for (Annotation annotation : parameterAnnotation) {
  219. @@ -696,17 +700,16 @@
  220.          return strategy.getDefaultParameterTypeExpression(parameterType);
  221.      }
  222.  
  223. -    private Expression createParameterUnmarshalExpressionForAnnotation(Class<?> clazz, Method method,
  224. -            Class<?> parameterType, Annotation annotation) {
  225. +    private Expression createParameterUnmarshalExpressionForAnnotation(Class<?> clazz, Method method, Class<?> parameterType, Annotation annotation) {
  226.          if (annotation instanceof Attachments) {
  227.              return ExpressionBuilder.attachmentsExpression();
  228.          } else if (annotation instanceof Property) {
  229. -            Property propertyAnnotation = (Property)annotation;
  230. +            Property propertyAnnotation = (Property) annotation;
  231.              return ExpressionBuilder.propertyExpression(propertyAnnotation.value());
  232.          } else if (annotation instanceof Properties) {
  233.              return ExpressionBuilder.propertiesExpression();
  234.          } else if (annotation instanceof Header) {
  235. -            Header headerAnnotation = (Header)annotation;
  236. +            Header headerAnnotation = (Header) annotation;
  237.              return ExpressionBuilder.headerExpression(headerAnnotation.value());
  238.          } else if (annotation instanceof Headers) {
  239.              return ExpressionBuilder.headersExpression();
  240. @@ -723,16 +726,15 @@
  241.                      AnnotationExpressionFactory expressionFactory = (AnnotationExpressionFactory) object;
  242.                      return expressionFactory.createExpression(camelContext, annotation, languageAnnotation, parameterType);
  243.                  } else {
  244. -                    LOG.warn("Ignoring bad annotation: " + languageAnnotation + "on method: " + method
  245. -                            + " which declares a factory: " + type.getName()
  246. -                            + " which does not implement " + AnnotationExpressionFactory.class.getName());
  247. +                    LOG.warn("Ignoring bad annotation: " + languageAnnotation + "on method: " + method + " which declares a factory: " + type.getName()
  248. +                                     + " which does not implement " + AnnotationExpressionFactory.class.getName());
  249.                  }
  250.              }
  251.          }
  252.  
  253.          return null;
  254.      }
  255. -    
  256. +
  257.      private static List<Method> getInterfaceMethods(Class<?> clazz) {
  258.          final List<Method> answer = new ArrayList<Method>();
  259.          for (Class<?> interfaceClazz : clazz.getInterfaces()) {
  260. @@ -822,7 +824,6 @@
  261.                      if (assignable != null && !assignable) {
  262.                          return false;
  263.                      }
  264. -
  265.                  } else {
  266.                      // there method has more parameters than was specified in the method name qualifiers
  267.                      return false;
  268. @@ -943,4 +944,47 @@
  269.          return null;
  270.      }
  271.  
  272. +    private static final class CacheKey {
  273. +        private final Class<?> type;
  274. +        private final Method explicitMethod;
  275. +        private final Class<? extends ParameterMappingStrategy> strategyClass;
  276. +
  277. +        public CacheKey(Class<?> type, Method explicitMethod, ParameterMappingStrategy strategy) {
  278. +            this.type = type;
  279. +            this.explicitMethod = explicitMethod;
  280. +            this.strategyClass = strategy.getClass();
  281. +        }
  282. +
  283. +        @Override
  284. +        public boolean equals(Object o) {
  285. +            if (this == o) {
  286. +                return true;
  287. +            }
  288. +            if (o == null || getClass() != o.getClass()) {
  289. +                return false;
  290. +            }
  291. +
  292. +            CacheKey cacheKey = (CacheKey) o;
  293. +
  294. +            if (explicitMethod != null ? !explicitMethod.equals(cacheKey.explicitMethod) : cacheKey.explicitMethod != null) {
  295. +                return false;
  296. +            }
  297. +            if (!strategyClass.equals(cacheKey.strategyClass)) {
  298. +                return false;
  299. +            }
  300. +            if (!type.equals(cacheKey.type)) {
  301. +                return false;
  302. +            }
  303. +
  304. +            return true;
  305. +        }
  306. +
  307. +        @Override
  308. +        public int hashCode() {
  309. +            int result = type.hashCode();
  310. +            result = 31 * result + (explicitMethod != null ? explicitMethod.hashCode() : 0);
  311. +            result = 31 * result + strategyClass.hashCode();
  312. +            return result;
  313. +        }
  314. +    }
  315.  }
  316. Index: src/test/java/org/apache/camel/component/bean/CamelSimpleExpressionPerfTest.java
  317. ===================================================================
  318. --- src/test/java/org/apache/camel/component/bean/CamelSimpleExpressionPerfTest.java    (revision 0)
  319. +++ src/test/java/org/apache/camel/component/bean/CamelSimpleExpressionPerfTest.java    (working copy)
  320. @@ -0,0 +1,59 @@
  321. +package org.apache.camel.component.bean;
  322. +
  323. +import java.util.*;
  324. +import org.apache.camel.CamelContext;
  325. +import org.apache.camel.ProducerTemplate;
  326. +import org.apache.camel.builder.RouteBuilder;
  327. +import org.apache.camel.impl.DefaultCamelContext;
  328. +import org.apache.camel.impl.SimpleRegistry;
  329. +import org.apache.camel.model.RouteDefinition;
  330. +import org.apache.camel.spi.Registry;
  331. +
  332. +public class CamelSimpleExpressionPerfTest {
  333. +    private static final int MESSAGE_LOOP_COUNT = 10000;
  334. +    private static final int TEST_EXECUTION_COUNT = 5;
  335. +
  336. +    public static void main(String[] args) throws Exception {
  337. +        long bodyOnly = executePerformanceTest(new SimpleRegistry(), "${body}");
  338. +        long bodyProperty = executePerformanceTest(new SimpleRegistry(), "${body[p]}");
  339. +
  340. +        SimpleRegistry registry = new SimpleRegistry();
  341. +        registry.put(BeanInfo.BEAN_INFO_CACHE_REGISTRY_KEY, new HashMap());
  342. +        long bodyPropertyWithCache = executePerformanceTest(registry, "${body[p]}");
  343. +
  344. +        System.out.printf("${body}: %dms%n", bodyOnly);
  345. +        System.out.printf("${body[p]} : %dms%n", bodyProperty);
  346. +        System.out.printf("${body[p]} with cache : %dms%n", bodyPropertyWithCache);
  347. +    }
  348. +
  349. +    private static long executePerformanceTest(Registry registry, final String simpleExpression) throws Exception {
  350. +        CamelContext ctx = new DefaultCamelContext(registry);
  351. +
  352. +        ctx.addRoutes(new RouteBuilder() {
  353. +            @Override
  354. +            public void configure() throws Exception {
  355. +                from("direct:start").loop(MESSAGE_LOOP_COUNT).setHeader("test").simple(simpleExpression).to("mock:plop");
  356. +            }
  357. +        });
  358. +
  359. +        ctx.start();
  360. +
  361. +        Map<String, String> body = new HashMap<String, String>();
  362. +        body.put("p", "q");
  363. +
  364. +        ProducerTemplate template = ctx.createProducerTemplate();
  365. +        // Initial one, it's a dry start, we don't care about this one.
  366. +        template.sendBody("direct:start", body);
  367. +
  368. +        // Measure the duration of the executions in nanoseconds
  369. +        long totalNsDuration = 0;
  370. +        for (int i = 0; i < TEST_EXECUTION_COUNT; i++) {
  371. +            long tick = System.nanoTime();
  372. +            template.sendBody("direct:start", body);
  373. +            totalNsDuration += System.nanoTime() - tick;
  374. +        }
  375. +
  376. +        // Return the average duration in milliseconds
  377. +        return totalNsDuration / TEST_EXECUTION_COUNT / 1000 / 1000;
  378. +    }
  379. +}
Advertisement
Add Comment
Please, Sign In to add comment