View Javadoc

1   /**
2    * Project MI+
3    *
4    * Copyright (c) 2013, Syed Muhammad Humayun - smhumayun@gmail.com
5    *
6    * This project includes software developed by Syed Muhammad Humayun - smhumayun@gmail.com
7    * http://www.smhumayun.com
8    *
9    * Licensed under the Apache License, Version 2.0 (the
10   * "License"); you may not use this file except in compliance
11   * with the License. You may obtain a copy of the License at:
12   *
13   * http://www.apache.org/licenses/LICENSE-2.0
14   *
15   * Unless required by applicable law or agreed to in writing,
16   * software distributed under the License is distributed on
17   * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18   * KIND, either express or implied. See the License for the
19   * specific language governing permissions and limitations
20   * under the License.
21   */
22  package com.smhumayun.mi_plus.impl;
23  
24  import com.smhumayun.mi_plus.*;
25  import com.smhumayun.mi_plus.util.Pair;
26  import com.smhumayun.mi_plus.util.Utils;
27  import org.apache.commons.beanutils.MethodUtils;
28  
29  import java.lang.reflect.Method;
30  import java.util.Arrays;
31  import java.util.LinkedHashMap;
32  import java.util.logging.Logger;
33  
34  /**
35   * {@link com.smhumayun.mi_plus.MIMethodResolver} implementation which resolves method based on the order of
36   * {@link com.smhumayun.mi_plus.MISupport#parentClasses()} and method resolution strategy of Apache
37   * Commons {@link MethodUtils#getMatchingAccessibleMethod(Class, String, Class[])}
38   *
39   * @author smhumayun
40   * @since 1.0
41   */
42  public final class MIMethodResolverImpl implements MIMethodResolver {
43  
44      /**
45       * Logger {@link Logger}
46       */
47      private Logger logger = Logger.getLogger(MIMethodResolverImpl.class.getName());
48  
49      /**
50       * Utils
51       */
52      private Utils utils = new Utils();
53  
54      /**
55       * Resolve method based on following strategy:
56       * - Iterate over composed objects (order will be the same as defined in {@link com.smhumayun.mi_plus.MISupport}
57       * - For each composed object, check if there's a matching 'accessible' method based on the algorithm defined by
58       * {@link MethodUtils#getAccessibleMethod(Class, String, Class[])} i.e. it finds an accessible method that matches
59       * the given name and has compatible parameters. Compatible parameters mean that every method parameter is
60       * assignable from the given parameters. In other words, it finds a method with the given name that will take the
61       * parameters given.
62       * - If a match is found, break the iteration and exit from the loop;
63       * - Return the corresponding composed object and the matched method
64       *
65       * @param miContainerClass      MI Container class
66       * @param composedObjects       map of composed objects
67       * @param methodCall            method call made on Proxy
68       * @param methodCallArgs        method call arguments
69       * @return resolved target method and object
70       * @throws com.smhumayun.mi_plus.MIException {@link com.smhumayun.mi_plus.MIException}
71       */
72      public Pair<Object, Method> resolve (Class miContainerClass, LinkedHashMap<Class, Object> composedObjects, Method methodCall
73              , Object[] methodCallArgs) throws MIException {
74          logger.info("resolve " + methodCall.toGenericString());
75          Class[] methodCallArgsClasses = utils.getClasses(methodCallArgs);
76          logger.fine("methodCallArgs classes = " + Arrays.toString(methodCallArgsClasses));
77          Object targetObject = null;
78          Method targetMethod = null;
79          for (Class composedObjectClass : composedObjects.keySet()) {
80              try
81              {
82                  targetMethod = MethodUtils.getMatchingAccessibleMethod(composedObjectClass, methodCall.getName()
83                          , methodCallArgsClasses);
84                  if(targetMethod != null)
85                  {
86                      logger.info("matching method found! " + targetMethod.toGenericString());
87                      targetObject = composedObjects.get(composedObjectClass);
88                      break;
89                  }
90              } catch (Exception e) { /* SWALLOW */ }
91          }
92          //if not found
93          if(targetMethod == null)
94              //throw exception
95              throw new UnsupportedOperationException("method '" + methodCall.toGenericString() + "' not found");
96          //else return the target object and method to caller
97          return new Pair<Object, Method>(targetObject, targetMethod);
98      }
99  
100 }